- Switch to structured logging and add telemetry

This commit is contained in:
Ryan Wagoner 2020-01-05 21:34:03 -05:00
parent 7d87416915
commit 8e637db459
25 changed files with 368 additions and 373 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", "-e", "-s", "/config/WebSubscriptions.json" ] CMD [ "mono", "OmniLinkBridge.exe", "-i", "-c", "/config/OmniLinkBridge.ini", "-e", "-s", "/config/WebSubscriptions.json", "-lf", "disable" ]

View file

@ -1,37 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup> </startup>
<log4net>
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date %-5level: %message%newline"/>
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Composite"/>
<datePattern value="yyyyMMdd"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="5MB"/>
<immediateFlush value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="WARN"/>
<levelMax value="FATAL"/>
</filter>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="TraceAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>
</log4net>
</configuration> </configuration>

View file

@ -1,5 +1,7 @@
using log4net; using OmniLinkBridge.Modules;
using OmniLinkBridge.Modules; using Serilog;
using Serilog.Context;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
@ -9,11 +11,13 @@ namespace OmniLinkBridge
{ {
public class CoreServer public class CoreServer
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private OmniLinkII omnilink; private OmniLinkII omnilink;
private readonly List<IModule> modules = new List<IModule>(); private readonly List<IModule> modules = new List<IModule>();
private readonly List<Task> tasks = new List<Task>(); private readonly List<Task> tasks = new List<Task>();
private readonly ManualResetEvent quitEvent = new ManualResetEvent(false);
private DateTime startTime;
public CoreServer() public CoreServer()
{ {
@ -23,11 +27,6 @@ namespace OmniLinkBridge
private void Server() private void Server()
{ {
Global.running = true;
log.Debug("Starting up server " +
Assembly.GetExecutingAssembly().GetName().Version.ToString());
// Controller connection // Controller connection
modules.Add(omnilink = new OmniLinkII(Global.controller_address, Global.controller_port, Global.controller_key1, Global.controller_key2)); modules.Add(omnilink = new OmniLinkII(Global.controller_address, Global.controller_port, Global.controller_key1, Global.controller_key2));
@ -43,6 +42,12 @@ namespace OmniLinkBridge
if(Global.mqtt_enabled) if(Global.mqtt_enabled)
modules.Add(new MQTTModule(omnilink)); modules.Add(new MQTTModule(omnilink));
startTime = DateTime.Now;
using (LogContext.PushProperty("Telemetry", "Startup"))
log.Information("Started version {Version} on {OperatingSystem} with {Modules}",
Assembly.GetExecutingAssembly().GetName().Version, Environment.OSVersion, modules);
// Startup modules // Startup modules
foreach (IModule module in modules) foreach (IModule module in modules)
{ {
@ -52,14 +57,11 @@ namespace OmniLinkBridge
})); }));
} }
// Wait for all threads to stop quitEvent.WaitOne();
Task.WaitAll(tasks.ToArray());
} }
public void Shutdown() public void Shutdown()
{ {
Global.running = false;
// Shutdown modules // Shutdown modules
foreach (IModule module in modules) foreach (IModule module in modules)
module.Shutdown(); module.Shutdown();
@ -68,7 +70,12 @@ namespace OmniLinkBridge
if (tasks != null) if (tasks != null)
Task.WaitAll(tasks.ToArray()); Task.WaitAll(tasks.ToArray());
log.Debug("Shutdown completed"); using (LogContext.PushProperty("Telemetry", "Shutdown"))
log.Information("Shutdown completed with uptime {Uptime}", (DateTime.Now - startTime).ToString());
Log.CloseAndFlush();
quitEvent.Set();
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
namespace OmniLinkBridge namespace OmniLinkBridge
{ {
@ -23,6 +24,11 @@ namespace OmniLinkBridge
return (b & (1 << pos)) != 0; return (b & (1 << pos)) != 0;
} }
public static string ToSpaceTitleCase(this string phrase)
{
return Regex.Replace(phrase, "(\\B[A-Z])", " $1");
}
public static List<int> ParseRanges(this string ranges) public static List<int> ParseRanges(this string ranges)
{ {
string[] groups = ranges.Split(','); string[] groups = ranges.Split(',');

View file

@ -7,10 +7,8 @@ namespace OmniLinkBridge
{ {
public abstract class Global public abstract class Global
{ {
public static bool running; public static bool DebugSettings { get; set; }
public static bool UseEnvironment { get; set; }
// Config File
public static string config_file;
// HAI / Leviton Omni Controller // HAI / Leviton Omni Controller
public static string controller_address; public static string controller_address;

View file

@ -1,6 +1,6 @@
using HAI_Shared; using HAI_Shared;
using log4net;
using OmniLinkBridge.OmniLink; using OmniLinkBridge.OmniLink;
using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -10,7 +10,7 @@ namespace OmniLinkBridge.MQTT
{ {
public class MessageProcessor public class MessageProcessor
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private readonly Regex regexTopic = new Regex(Global.mqtt_prefix + "/([A-Za-z]+)([0-9]+)/(.*)", RegexOptions.Compiled); private readonly Regex regexTopic = new Regex(Global.mqtt_prefix + "/([A-Za-z]+)([0-9]+)/(.*)", RegexOptions.Compiled);
@ -33,7 +33,8 @@ namespace OmniLinkBridge.MQTT
|| !ushort.TryParse(match.Groups[2].Value, out ushort id)) || !ushort.TryParse(match.Groups[2].Value, out ushort id))
return; return;
log.Debug($"Received: Type: {type.ToString()}, Id: {id}, Command: {topic.ToString()}, Value: {payload}"); log.Debug("Received: Type: {type}, Id: {id}, Command: {command}, Value: {value}",
type.ToString(), id, topic.ToString(), payload);
if (type == CommandTypes.area && id <= OmniLink.Controller.Areas.Count) if (type == CommandTypes.area && id <= OmniLink.Controller.Areas.Count)
ProcessAreaReceived(OmniLink.Controller.Areas[id], topic, payload); ProcessAreaReceived(OmniLink.Controller.Areas[id], topic, payload);
@ -68,7 +69,7 @@ namespace OmniLinkBridge.MQTT
if (area.Number == 0) if (area.Number == 0)
log.Debug("SetArea: 0 implies all areas will be changed"); log.Debug("SetArea: 0 implies all areas will be changed");
log.Debug("SetArea: " + area.Number + " to " + cmd.ToString().Replace("arm_", "").Replace("_", " ")); log.Debug("SetArea: {id} to {value}", area.Number, cmd.ToString().Replace("arm_", "").Replace("_", " "));
OmniLink.SendCommand(AreaMapping[cmd], 0, (ushort)area.Number); OmniLink.SendCommand(AreaMapping[cmd], 0, (ushort)area.Number);
} }
} }
@ -83,7 +84,7 @@ namespace OmniLinkBridge.MQTT
{ {
if (command == Topic.command && Enum.TryParse(payload, true, out ZoneCommands cmd)) if (command == Topic.command && Enum.TryParse(payload, true, out ZoneCommands cmd))
{ {
log.Debug("SetZone: " + zone.Number + " to " + payload); log.Debug("SetZone: {id} to {value}", zone.Number, payload);
OmniLink.SendCommand(ZoneMapping[cmd], 0, (ushort)zone.Number); OmniLink.SendCommand(ZoneMapping[cmd], 0, (ushort)zone.Number);
} }
} }
@ -100,13 +101,13 @@ namespace OmniLinkBridge.MQTT
{ {
if (string.Compare(unit.ToState(), cmd.ToString()) != 0) if (string.Compare(unit.ToState(), cmd.ToString()) != 0)
{ {
log.Debug("SetUnit: " + unit.Number + " to " + cmd.ToString()); log.Debug("SetUnit: {id} to {value}", unit.Number, cmd.ToString());
OmniLink.SendCommand(UnitMapping[cmd], 0, (ushort)unit.Number); OmniLink.SendCommand(UnitMapping[cmd], 0, (ushort)unit.Number);
} }
} }
else if (command == Topic.brightness_command && int.TryParse(payload, out int unitValue)) else if (command == Topic.brightness_command && int.TryParse(payload, out int unitValue))
{ {
log.Debug("SetUnit: " + unit.Number + " to " + payload + "%"); log.Debug("SetUnit: {id} to {value}%", unit.Number, payload);
OmniLink.SendCommand(enuUnitCommand.Level, BitConverter.GetBytes(unitValue)[0], (ushort)unit.Number); OmniLink.SendCommand(enuUnitCommand.Level, BitConverter.GetBytes(unitValue)[0], (ushort)unit.Number);
@ -129,7 +130,8 @@ namespace OmniLinkBridge.MQTT
} }
int temp = tempLow.ToOmniTemp(); int temp = tempLow.ToOmniTemp();
log.Debug("SetThermostatHeatSetpoint: " + thermostat.Number + " to " + payload + tempUnit + "(" + temp + ")"); log.Debug("SetThermostatHeatSetpoint: {id} to {value}{temperatureUnit} ({temp})",
thermostat.Number, payload, tempUnit, temp);
OmniLink.SendCommand(enuUnitCommand.SetLowSetPt, BitConverter.GetBytes(temp)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.SetLowSetPt, BitConverter.GetBytes(temp)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.temperature_cool_command && double.TryParse(payload, out double tempHigh)) else if (command == Topic.temperature_cool_command && double.TryParse(payload, out double tempHigh))
@ -142,35 +144,36 @@ namespace OmniLinkBridge.MQTT
} }
int temp = tempHigh.ToOmniTemp(); int temp = tempHigh.ToOmniTemp();
log.Debug("SetThermostatCoolSetpoint: " + thermostat.Number + " to " + payload + tempUnit + "(" + temp + ")"); log.Debug("SetThermostatCoolSetpoint: {id} to {value}{temperatureUnit} ({temp})",
thermostat.Number, payload, tempUnit, temp);
OmniLink.SendCommand(enuUnitCommand.SetHighSetPt, BitConverter.GetBytes(temp)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.SetHighSetPt, BitConverter.GetBytes(temp)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.humidify_command && double.TryParse(payload, out double humidify)) else if (command == Topic.humidify_command && double.TryParse(payload, out double humidify))
{ {
// Humidity is reported where Fahrenheit temperatures 0-100 correspond to 0-100% relative humidity // Humidity is reported where Fahrenheit temperatures 0-100 correspond to 0-100% relative humidity
int level = humidify.ToCelsius().ToOmniTemp(); int level = humidify.ToCelsius().ToOmniTemp();
log.Debug("SetThermostatHumidifySetpoint: " + thermostat.Number + " to " + payload + "% (" + level + ")"); log.Debug("SetThermostatHumidifySetpoint: {id} to {value}% ({level})", thermostat.Number, payload, level);
OmniLink.SendCommand(enuUnitCommand.SetHumidifySetPt, BitConverter.GetBytes(level)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.SetHumidifySetPt, BitConverter.GetBytes(level)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.dehumidify_command && double.TryParse(payload, out double dehumidify)) else if (command == Topic.dehumidify_command && double.TryParse(payload, out double dehumidify))
{ {
int level = dehumidify.ToCelsius().ToOmniTemp(); int level = dehumidify.ToCelsius().ToOmniTemp();
log.Debug("SetThermostatDehumidifySetpoint: " + thermostat.Number + " to " + payload + "% (" + level + ")"); log.Debug("SetThermostatDehumidifySetpoint: {id} to {value}% ({level})", thermostat.Number, payload, level);
OmniLink.SendCommand(enuUnitCommand.SetDeHumidifySetPt, BitConverter.GetBytes(level)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.SetDeHumidifySetPt, BitConverter.GetBytes(level)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.mode_command && Enum.TryParse(payload, true, out enuThermostatMode mode)) else if (command == Topic.mode_command && Enum.TryParse(payload, true, out enuThermostatMode mode))
{ {
log.Debug("SetThermostatMode: " + thermostat.Number + " to " + payload); log.Debug("SetThermostatMode: {id} to {value}", thermostat.Number, payload);
OmniLink.SendCommand(enuUnitCommand.Mode, BitConverter.GetBytes((int)mode)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.Mode, BitConverter.GetBytes((int)mode)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.fan_mode_command && Enum.TryParse(payload, true, out enuThermostatFanMode fanMode)) else if (command == Topic.fan_mode_command && Enum.TryParse(payload, true, out enuThermostatFanMode fanMode))
{ {
log.Debug("SetThermostatFanMode: " + thermostat.Number + " to " + payload); log.Debug("SetThermostatFanMode: {id} to {value}", thermostat.Number, payload);
OmniLink.SendCommand(enuUnitCommand.Fan, BitConverter.GetBytes((int)fanMode)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.Fan, BitConverter.GetBytes((int)fanMode)[0], (ushort)thermostat.Number);
} }
else if (command == Topic.hold_command && Enum.TryParse(payload, true, out enuThermostatHoldMode holdMode)) else if (command == Topic.hold_command && Enum.TryParse(payload, true, out enuThermostatHoldMode holdMode))
{ {
log.Debug("SetThermostatHold: " + thermostat.Number + " to " + payload); log.Debug("SetThermostatHold: {id} to {value}", thermostat.Number, payload);
OmniLink.SendCommand(enuUnitCommand.Hold, BitConverter.GetBytes((int)holdMode)[0], (ushort)thermostat.Number); OmniLink.SendCommand(enuUnitCommand.Hold, BitConverter.GetBytes((int)holdMode)[0], (ushort)thermostat.Number);
} }
} }
@ -179,7 +182,7 @@ namespace OmniLinkBridge.MQTT
{ {
if (command == Topic.command && Enum.TryParse(payload, true, out UnitCommands cmd) && cmd == UnitCommands.ON) if (command == Topic.command && Enum.TryParse(payload, true, out UnitCommands cmd) && cmd == UnitCommands.ON)
{ {
log.Debug("PushButton: " + button.Number); log.Debug("PushButton: {id}", button.Number);
OmniLink.SendCommand(enuUnitCommand.Button, 0, (ushort)button.Number); OmniLink.SendCommand(enuUnitCommand.Button, 0, (ushort)button.Number);
} }
} }
@ -196,7 +199,7 @@ namespace OmniLinkBridge.MQTT
{ {
if (command == Topic.command && Enum.TryParse(payload, true, out MessageCommands cmd)) if (command == Topic.command && Enum.TryParse(payload, true, out MessageCommands cmd))
{ {
log.Debug("SetMessage: " + message.Number + " to " + cmd.ToString().Replace("_", " ")); log.Debug("SetMessage: {id} to {value}", message.Number, cmd.ToString().Replace("_", " "));
byte par = 0; byte par = 0;
if (cmd == MessageCommands.show_no_beep) if (cmd == MessageCommands.show_no_beep)

View file

@ -1,6 +1,6 @@
using log4net; using OmniLinkBridge.Notifications;
using OmniLinkBridge.Notifications;
using OmniLinkBridge.OmniLink; using OmniLinkBridge.OmniLink;
using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@ -12,7 +12,9 @@ namespace OmniLinkBridge.Modules
{ {
public class LoggerModule : IModule public class LoggerModule : IModule
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private bool running = true;
private readonly OmniLinkII omnilink; private readonly OmniLinkII omnilink;
private readonly List<string> alarms = new List<string>(); private readonly List<string> alarms = new List<string>();
@ -41,26 +43,22 @@ namespace OmniLinkBridge.Modules
{ {
if (Global.mysql_logging) if (Global.mysql_logging)
{ {
log.Info("Connecting to database"); log.Information("Connecting to database");
mysql_conn = new OdbcConnection(Global.mysql_connection); mysql_conn = new OdbcConnection(Global.mysql_connection);
// Must make an initial connection
if (!DBOpen())
Environment.Exit(1);
} }
while (true) while (true)
{ {
// End gracefully when not logging or database queue empty // End gracefully when not logging or database queue empty
if (!Global.running && (!Global.mysql_logging || DBQueueCount() == 0)) if (!running && (!Global.mysql_logging || DBQueueCount() == 0))
break; break;
// Make sure database connection is active // Make sure database connection is active
if (Global.mysql_logging && mysql_conn.State != ConnectionState.Open) if (Global.mysql_logging && mysql_conn.State != ConnectionState.Open)
{ {
// Nothing we can do if shutting down // Nothing we can do if shutting down
if (!Global.running) if (!running)
break; break;
if (mysql_retry < DateTime.Now) if (mysql_retry < DateTime.Now)
@ -100,11 +98,11 @@ namespace OmniLinkBridge.Modules
{ {
if (mysql_conn.State != ConnectionState.Open) if (mysql_conn.State != ConnectionState.Open)
{ {
log.Warn("Lost connection to database"); log.Warning("Lost connection to database");
} }
else else
{ {
log.Error("Error executing query\r\n" + query, ex); log.Error(ex, "Error executing {query}", query);
// Prevent an endless loop from failed query // Prevent an endless loop from failed query
lock (mysql_lock) lock (mysql_lock)
@ -119,6 +117,7 @@ namespace OmniLinkBridge.Modules
public void Shutdown() public void Shutdown()
{ {
running = false;
trigger.Set(); trigger.Set();
} }
@ -198,7 +197,7 @@ namespace OmniLinkBridge.Modules
e.Area.AreaDuressAlarmText + "','" + status + "')"); e.Area.AreaDuressAlarmText + "','" + status + "')");
if (Global.verbose_area) if (Global.verbose_area)
log.Debug("AreaStatus " + e.ID + " " + e.Area.Name + ", Status: " + status); log.Verbose("AreaStatus {id} {name}, Status: {status}", e.ID, e.Area.Name, status);
if (Global.notify_area && e.Area.LastMode != e.Area.AreaMode) if (Global.notify_area && e.Area.LastMode != e.Area.AreaMode)
Notification.Notify("Security", e.Area.Name + " " + e.Area.ModeText()); Notification.Notify("Security", e.Area.Name + " " + e.Area.ModeText());
@ -213,9 +212,9 @@ namespace OmniLinkBridge.Modules
if (Global.verbose_zone) if (Global.verbose_zone)
{ {
if (e.Zone.IsTemperatureZone()) if (e.Zone.IsTemperatureZone())
log.Debug("ZoneStatus " + e.ID + " " + e.Zone.Name + ", Temp: " + e.Zone.TempText()); log.Verbose("ZoneStatus {id} {name}, Temp: {temp}", e.ID, e.Zone.Name, e.Zone.TempText());
else else
log.Debug("ZoneStatus " + e.ID + " " + e.Zone.Name + ", Status: " + e.Zone.StatusText()); log.Verbose("ZoneStatus {id} {name}, Status: {status}", e.ID, e.Zone.Name, e.Zone.StatusText());
} }
} }
@ -241,13 +240,15 @@ namespace OmniLinkBridge.Modules
// Ignore events fired by thermostat polling // Ignore events fired by thermostat polling
if (!e.EventTimer && Global.verbose_thermostat) if (!e.EventTimer && Global.verbose_thermostat)
log.Debug("ThermostatStatus " + e.ID + " " + e.Thermostat.Name + log.Verbose("ThermostatStatus {id} {name}, Status: {temp} {status}, " +
", Status: " + e.Thermostat.TempText() + " " + e.Thermostat.HorC_StatusText() + "Heat {heat}, Cool: {cool}, Mode: {mode}, Fan: {fan}, Hold: {hold}",
", Heat: " + e.Thermostat.HeatSetpointText() + e.ID, e.Thermostat.Name,
", Cool: " + e.Thermostat.CoolSetpointText() + e.Thermostat.TempText(), e.Thermostat.HorC_StatusText(),
", Mode: " + e.Thermostat.ModeText() + e.Thermostat.HeatSetpointText(),
", Fan: " + e.Thermostat.FanModeText() + e.Thermostat.CoolSetpointText(),
", Hold: " + e.Thermostat.HoldStatusText()); e.Thermostat.ModeText(),
e.Thermostat.FanModeText(),
e.Thermostat.HoldStatusText());
} }
private void Omnilink_OnUnitStatus(object sender, UnitStatusEventArgs e) private void Omnilink_OnUnitStatus(object sender, UnitStatusEventArgs e)
@ -266,7 +267,7 @@ namespace OmniLinkBridge.Modules
status + "','" + e.Unit.Status + "','" + e.Unit.StatusTime + "')"); status + "','" + e.Unit.Status + "','" + e.Unit.StatusTime + "')");
if (Global.verbose_unit) if (Global.verbose_unit)
log.Debug("UnitStatus " + e.ID + " " + e.Unit.Name + ", Status: " + status); log.Verbose("UnitStatus {id} {name}, Status: {status}", e.ID, e.Unit.Name, status);
} }
private void Omnilink_OnMessageStatus(object sender, MessageStatusEventArgs e) private void Omnilink_OnMessageStatus(object sender, MessageStatusEventArgs e)
@ -276,7 +277,7 @@ namespace OmniLinkBridge.Modules
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + e.ID + "','" + e.Message.Name + "','" + e.Message.StatusText() + "')"); VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + e.ID + "','" + e.Message.Name + "','" + e.Message.StatusText() + "')");
if (Global.verbose_message) if (Global.verbose_message)
log.Debug("MessageStatus " + e.ID + " " + e.Message.Name + ", " + e.Message.StatusText()); log.Verbose("MessageStatus {id} {name}, Status: {status}", e.ID, e.Message.Name, e.Message.StatusText());
if (Global.notify_message) if (Global.notify_message)
Notification.Notify("Message", e.ID + " " + e.Message.Name + ", " + e.Message.StatusText()); Notification.Notify("Message", e.ID + " " + e.Message.Name + ", " + e.Message.StatusText());
@ -289,7 +290,7 @@ namespace OmniLinkBridge.Modules
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + e.Type.ToString() + "','" + e.Value + "')"); VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + e.Type.ToString() + "','" + e.Value + "')");
if (Global.verbose_event) if (Global.verbose_event)
log.Debug("SystemEvent " + e.Type.ToString() + " " + e.Value); log.Verbose("SystemEvent {name} {status}", e.Type.ToString(), e.Value);
if (e.SendNotification) if (e.SendNotification)
Notification.Notify("SystemEvent", e.Type.ToString() + " " + e.Value); Notification.Notify("SystemEvent", e.Type.ToString() + " " + e.Value);
@ -306,7 +307,7 @@ namespace OmniLinkBridge.Modules
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("Failed to connect to database", ex); log.Error(ex, "Failed to connect to database");
mysql_retry = DateTime.Now.AddMinutes(1); mysql_retry = DateTime.Now.AddMinutes(1);
return false; return false;
} }

View file

@ -1,5 +1,4 @@
using HAI_Shared; using HAI_Shared;
using log4net;
using MQTTnet; using MQTTnet;
using MQTTnet.Client; using MQTTnet.Client;
using MQTTnet.Client.Connecting; using MQTTnet.Client.Connecting;
@ -11,6 +10,7 @@ using MQTTnet.Protocol;
using Newtonsoft.Json; using Newtonsoft.Json;
using OmniLinkBridge.MQTT; using OmniLinkBridge.MQTT;
using OmniLinkBridge.OmniLink; using OmniLinkBridge.OmniLink;
using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -22,7 +22,7 @@ namespace OmniLinkBridge.Modules
{ {
public class MQTTModule : IModule public class MQTTModule : IModule
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
public static DeviceRegistry MqttDeviceRegistry { get; set; } public static DeviceRegistry MqttDeviceRegistry { get; set; }
@ -90,7 +90,7 @@ namespace OmniLinkBridge.Modules
if (ControllerConnected) if (ControllerConnected)
PublishConfig(); PublishConfig();
}); });
MqttClient.ConnectingFailedHandler = new ConnectingFailedHandlerDelegate((e) => log.Debug("Error connecting " + e.Exception.Message)); MqttClient.ConnectingFailedHandler = new ConnectingFailedHandlerDelegate((e) => log.Error("Error connecting {reason}", e.Exception.Message));
MqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate((e) => log.Debug("Disconnected")); MqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate((e) => log.Debug("Disconnected"));
MqttClient.StartAsync(manoptions); MqttClient.StartAsync(manoptions);
@ -118,8 +118,7 @@ namespace OmniLinkBridge.Modules
// Wait until shutdown // Wait until shutdown
trigger.WaitOne(); trigger.WaitOne();
log.Debug("Publishing controller offline"); PublishControllerStatus("offline");
PublishAsync($"{Global.mqtt_prefix}/status", "offline");
MqttClient.StopAsync(); MqttClient.StopAsync();
} }
@ -142,10 +141,13 @@ namespace OmniLinkBridge.Modules
ControllerConnected = false; ControllerConnected = false;
if (MqttClient.IsConnected) if (MqttClient.IsConnected)
{ PublishControllerStatus("offline");
log.Debug("Publishing controller offline"); }
PublishAsync($"{Global.mqtt_prefix}/status", "offline");
} private void PublishControllerStatus(string status)
{
log.Information("Publishing controller {status}", status);
PublishAsync($"{Global.mqtt_prefix}/status", status);
} }
private void PublishConfig() private void PublishConfig()
@ -157,15 +159,14 @@ namespace OmniLinkBridge.Modules
PublishButtons(); PublishButtons();
PublishMessages(); PublishMessages();
log.Debug("Publishing controller online"); PublishControllerStatus("online");
PublishAsync($"{Global.mqtt_prefix}/status", "online");
PublishAsync($"{Global.mqtt_prefix}/model", OmniLink.Controller.GetModelText()); PublishAsync($"{Global.mqtt_prefix}/model", OmniLink.Controller.GetModelText());
PublishAsync($"{Global.mqtt_prefix}/version", OmniLink.Controller.GetVersionText()); PublishAsync($"{Global.mqtt_prefix}/version", OmniLink.Controller.GetVersionText());
} }
private void PublishAreas() private void PublishAreas()
{ {
log.Debug("Publishing areas"); log.Debug("Publishing {type}", "areas");
for (ushort i = 1; i <= OmniLink.Controller.Areas.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Areas.Count; i++)
{ {
@ -214,7 +215,7 @@ namespace OmniLinkBridge.Modules
private void PublishZones() private void PublishZones()
{ {
log.Debug("Publishing zones"); log.Debug("Publishing {type}", "zones");
for (ushort i = 1; i <= OmniLink.Controller.Zones.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Zones.Count; i++)
{ {
@ -255,7 +256,7 @@ namespace OmniLinkBridge.Modules
private void PublishUnits() private void PublishUnits()
{ {
log.Debug("Publishing units"); log.Debug("Publishing {type}", "units");
for (ushort i = 1; i <= OmniLink.Controller.Units.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Units.Count; i++)
{ {
@ -289,7 +290,7 @@ namespace OmniLinkBridge.Modules
private void PublishThermostats() private void PublishThermostats()
{ {
log.Debug("Publishing thermostats"); log.Debug("Publishing {type}", "thermostats");
for (ushort i = 1; i <= OmniLink.Controller.Thermostats.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Thermostats.Count; i++)
{ {
@ -318,7 +319,7 @@ namespace OmniLinkBridge.Modules
private void PublishButtons() private void PublishButtons()
{ {
log.Debug("Publishing buttons"); log.Debug("Publishing {type}", "buttons");
for (ushort i = 1; i <= OmniLink.Controller.Buttons.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Buttons.Count; i++)
{ {
@ -342,7 +343,7 @@ namespace OmniLinkBridge.Modules
private void PublishMessages() private void PublishMessages()
{ {
log.Debug("Publishing messages"); log.Debug("Publishing {type}", "messages");
for (ushort i = 1; i <= OmniLink.Controller.Messages.Count; i++) for (ushort i = 1; i <= OmniLink.Controller.Messages.Count; i++)
{ {

View file

@ -1,6 +1,7 @@
using HAI_Shared; using HAI_Shared;
using OmniLinkBridge.OmniLink; using OmniLinkBridge.OmniLink;
using log4net; using Serilog;
using Serilog.Context;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -12,7 +13,9 @@ namespace OmniLinkBridge.Modules
{ {
public class OmniLinkII : IModule, IOmniLinkII public class OmniLinkII : IModule, IOmniLinkII
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private bool running = true;
// OmniLink Controller // OmniLink Controller
public clsHAC Controller { get; private set; } public clsHAC Controller { get; private set; }
@ -54,7 +57,7 @@ namespace OmniLinkBridge.Modules
public void Startup() public void Startup()
{ {
while (Global.running) while(running)
{ {
// Make sure controller connection is active // Make sure controller connection is active
if (Controller.Connection.ConnectionState == enuOmniLinkConnectionState.Offline && if (Controller.Connection.ConnectionState == enuOmniLinkConnectionState.Offline &&
@ -71,6 +74,7 @@ namespace OmniLinkBridge.Modules
public void Shutdown() public void Shutdown()
{ {
running = false;
trigger.Set(); trigger.Set();
} }
@ -92,7 +96,7 @@ namespace OmniLinkBridge.Modules
private void Disconnect() private void Disconnect()
{ {
log.Info("CONNECTION STATUS: Disconnecting"); log.Debug("Controller Status: {connectionStatus}", "Disconnecting");
if (Controller.Connection.ConnectionState != enuOmniLinkConnectionState.Offline) if (Controller.Connection.ConnectionState != enuOmniLinkConnectionState.Offline)
Controller.Connection.Disconnect(); Controller.Connection.Disconnect();
@ -100,187 +104,86 @@ namespace OmniLinkBridge.Modules
private void HandleConnectStatus(enuOmniLinkCommStatus CS) private void HandleConnectStatus(enuOmniLinkCommStatus CS)
{ {
var status = CS.ToString().ToSpaceTitleCase();
switch (CS) switch (CS)
{ {
case enuOmniLinkCommStatus.NoReply: case enuOmniLinkCommStatus.Connecting:
log.Error("CONNECTION STATUS: No Reply"); log.Debug("Controller Status: {connectionStatus}", status);
break;
case enuOmniLinkCommStatus.UnrecognizedReply:
log.Error("CONNECTION STATUS: Unrecognized Reply");
break;
case enuOmniLinkCommStatus.UnsupportedProtocol:
log.Error("CONNECTION STATUS: Unsupported Protocol");
break;
case enuOmniLinkCommStatus.ClientSessionTerminated:
log.Error("CONNECTION STATUS: Client Session Terminated");
break;
case enuOmniLinkCommStatus.ControllerSessionTerminated:
log.Error("CONNECTION STATUS: Controller Session Terminated");
break;
case enuOmniLinkCommStatus.CannotStartNewSession:
log.Error("CONNECTION STATUS: Cannot Start New Session");
break;
case enuOmniLinkCommStatus.LoginFailed:
log.Error("CONNECTION STATUS: Login Failed");
break;
case enuOmniLinkCommStatus.UnableToOpenSocket:
log.Error("CONNECTION STATUS: Unable To Open Socket");
break;
case enuOmniLinkCommStatus.UnableToConnect:
log.Error("CONNECTION STATUS: Unable To Connect");
break;
case enuOmniLinkCommStatus.SocketClosed:
log.Error("CONNECTION STATUS: Socket Closed");
break;
case enuOmniLinkCommStatus.UnexpectedError:
log.Error("CONNECTION STATUS: Unexpected Error");
break;
case enuOmniLinkCommStatus.UnableToCreateSocket:
log.Error("CONNECTION STATUS: Unable To Create Socket");
break;
case enuOmniLinkCommStatus.Retrying:
log.Warn("CONNECTION STATUS: Retrying");
break; break;
case enuOmniLinkCommStatus.Connected: case enuOmniLinkCommStatus.Connected:
IdentifyController(); IdentifyController();
break; break;
case enuOmniLinkCommStatus.Connecting:
log.Info("CONNECTION STATUS: Connecting");
break;
case enuOmniLinkCommStatus.Disconnected: case enuOmniLinkCommStatus.Disconnected:
log.Info("CONNECTION STATUS: Disconnected"); log.Information("Controller Status: {connectionStatus}", status);
OnDisconnect?.Invoke(this, new EventArgs()); OnDisconnect?.Invoke(this, new EventArgs());
break; break;
case enuOmniLinkCommStatus.InterruptedFunctionCall: case enuOmniLinkCommStatus.InterruptedFunctionCall:
if (Global.running) if (running)
log.Error("CONNECTION STATUS: Interrupted Function Call"); log.Error("Controller Status: {connectionStatus}", status);
break;
case enuOmniLinkCommStatus.PermissionDenied:
log.Error("CONNECTION STATUS: Permission Denied");
break;
case enuOmniLinkCommStatus.BadAddress:
log.Error("CONNECTION STATUS: Bad Address");
break;
case enuOmniLinkCommStatus.InvalidArgument:
log.Error("CONNECTION STATUS: Invalid Argument");
break;
case enuOmniLinkCommStatus.TooManyOpenFiles:
log.Error("CONNECTION STATUS: Too Many Open Files");
break;
case enuOmniLinkCommStatus.ResourceTemporarilyUnavailable:
log.Error("CONNECTION STATUS: Resource Temporarily Unavailable");
break; break;
case enuOmniLinkCommStatus.Retrying:
case enuOmniLinkCommStatus.OperationNowInProgress: case enuOmniLinkCommStatus.OperationNowInProgress:
log.Warn("CONNECTION STATUS: Operation Now In Progress");
break;
case enuOmniLinkCommStatus.OperationAlreadyInProgress: case enuOmniLinkCommStatus.OperationAlreadyInProgress:
log.Warn("CONNECTION STATUS: Operation Already In Progress");
break;
case enuOmniLinkCommStatus.SocketOperationOnNonSocket:
log.Error("CONNECTION STATUS: Socket Operation On Non Socket");
break;
case enuOmniLinkCommStatus.DestinationAddressRequired:
log.Error("CONNECTION STATUS: Destination Address Required");
break;
case enuOmniLinkCommStatus.MessgeTooLong:
log.Error("CONNECTION STATUS: Message Too Long");
break;
case enuOmniLinkCommStatus.WrongProtocolType:
log.Error("CONNECTION STATUS: Wrong Protocol Type");
break;
case enuOmniLinkCommStatus.BadProtocolOption:
log.Error("CONNECTION STATUS: Bad Protocol Option");
break;
case enuOmniLinkCommStatus.ProtocolNotSupported:
log.Error("CONNECTION STATUS: Protocol Not Supported");
break;
case enuOmniLinkCommStatus.SocketTypeNotSupported:
log.Error("CONNECTION STATUS: Socket Type Not Supported");
break;
case enuOmniLinkCommStatus.OperationNotSupported:
log.Error("CONNECTION STATUS: Operation Not Supported");
break;
case enuOmniLinkCommStatus.ProtocolFamilyNotSupported:
log.Error("CONNECTION STATUS: Protocol Family Not Supported");
break;
case enuOmniLinkCommStatus.AddressFamilyNotSupported:
log.Error("CONNECTION STATUS: Address Family Not Supported");
break;
case enuOmniLinkCommStatus.AddressInUse:
log.Error("CONNECTION STATUS: Address In Use");
break;
case enuOmniLinkCommStatus.AddressNotAvailable:
log.Error("CONNECTION STATUS: Address Not Available");
break;
case enuOmniLinkCommStatus.NetworkIsDown:
log.Error("CONNECTION STATUS: Network Is Down");
break;
case enuOmniLinkCommStatus.NetworkIsUnreachable:
log.Error("CONNECTION STATUS: Network Is Unreachable");
break;
case enuOmniLinkCommStatus.NetworkReset:
log.Error("CONNECTION STATUS: Network Reset");
break;
case enuOmniLinkCommStatus.ConnectionAborted:
log.Error("CONNECTION STATUS: Connection Aborted");
break;
case enuOmniLinkCommStatus.ConnectionResetByPeer:
log.Error("CONNECTION STATUS: Connection Reset By Peer");
break;
case enuOmniLinkCommStatus.NoBufferSpaceAvailable:
log.Error("CONNECTION STATUS: No Buffer Space Available");
break;
case enuOmniLinkCommStatus.AlreadyConnected: case enuOmniLinkCommStatus.AlreadyConnected:
log.Warn("CONNECTION STATUS: Already Connected"); log.Warning("Controller Status: {connectionStatus}", status);
break; break;
case enuOmniLinkCommStatus.NoReply:
case enuOmniLinkCommStatus.UnrecognizedReply:
case enuOmniLinkCommStatus.UnsupportedProtocol:
case enuOmniLinkCommStatus.ClientSessionTerminated:
case enuOmniLinkCommStatus.ControllerSessionTerminated:
case enuOmniLinkCommStatus.CannotStartNewSession:
case enuOmniLinkCommStatus.LoginFailed:
case enuOmniLinkCommStatus.UnableToOpenSocket:
case enuOmniLinkCommStatus.UnableToConnect:
case enuOmniLinkCommStatus.SocketClosed:
case enuOmniLinkCommStatus.UnexpectedError:
case enuOmniLinkCommStatus.UnableToCreateSocket:
case enuOmniLinkCommStatus.PermissionDenied:
case enuOmniLinkCommStatus.BadAddress:
case enuOmniLinkCommStatus.InvalidArgument:
case enuOmniLinkCommStatus.TooManyOpenFiles:
case enuOmniLinkCommStatus.ResourceTemporarilyUnavailable:
case enuOmniLinkCommStatus.SocketOperationOnNonSocket:
case enuOmniLinkCommStatus.DestinationAddressRequired:
case enuOmniLinkCommStatus.MessgeTooLong:
case enuOmniLinkCommStatus.WrongProtocolType:
case enuOmniLinkCommStatus.BadProtocolOption:
case enuOmniLinkCommStatus.ProtocolNotSupported:
case enuOmniLinkCommStatus.SocketTypeNotSupported:
case enuOmniLinkCommStatus.OperationNotSupported:
case enuOmniLinkCommStatus.ProtocolFamilyNotSupported:
case enuOmniLinkCommStatus.AddressFamilyNotSupported:
case enuOmniLinkCommStatus.AddressInUse:
case enuOmniLinkCommStatus.AddressNotAvailable:
case enuOmniLinkCommStatus.NetworkIsDown:
case enuOmniLinkCommStatus.NetworkIsUnreachable:
case enuOmniLinkCommStatus.NetworkReset:
case enuOmniLinkCommStatus.ConnectionAborted:
case enuOmniLinkCommStatus.ConnectionResetByPeer:
case enuOmniLinkCommStatus.NoBufferSpaceAvailable:
case enuOmniLinkCommStatus.NotConnected: case enuOmniLinkCommStatus.NotConnected:
log.Error("CONNECTION STATUS: Not Connected");
break;
case enuOmniLinkCommStatus.CannotSendAfterShutdown: case enuOmniLinkCommStatus.CannotSendAfterShutdown:
log.Error("CONNECTION STATUS: Cannot Send After Shutdown");
break;
case enuOmniLinkCommStatus.ConnectionTimedOut: case enuOmniLinkCommStatus.ConnectionTimedOut:
log.Error("CONNECTION STATUS: Connection Timed Out");
break;
case enuOmniLinkCommStatus.ConnectionRefused: case enuOmniLinkCommStatus.ConnectionRefused:
log.Error("CONNECTION STATUS: Connection Refused");
break;
case enuOmniLinkCommStatus.HostIsDown: case enuOmniLinkCommStatus.HostIsDown:
log.Error("CONNECTION STATUS: Host Is Down");
break;
case enuOmniLinkCommStatus.HostUnreachable: case enuOmniLinkCommStatus.HostUnreachable:
log.Error("CONNECTION STATUS: Host Unreachable");
break;
case enuOmniLinkCommStatus.TooManyProcesses: case enuOmniLinkCommStatus.TooManyProcesses:
log.Error("CONNECTION STATUS: Too Many Processes");
break;
case enuOmniLinkCommStatus.NetworkSubsystemIsUnavailable: case enuOmniLinkCommStatus.NetworkSubsystemIsUnavailable:
log.Error("CONNECTION STATUS: Network Subsystem Is Unavailable");
break;
case enuOmniLinkCommStatus.UnsupportedVersion: case enuOmniLinkCommStatus.UnsupportedVersion:
log.Error("CONNECTION STATUS: Unsupported Version");
break;
case enuOmniLinkCommStatus.NotInitialized: case enuOmniLinkCommStatus.NotInitialized:
log.Error("CONNECTION STATUS: Not Initialized");
break;
case enuOmniLinkCommStatus.ShutdownInProgress: case enuOmniLinkCommStatus.ShutdownInProgress:
log.Error("CONNECTION STATUS: Shutdown In Progress");
break;
case enuOmniLinkCommStatus.ClassTypeNotFound: case enuOmniLinkCommStatus.ClassTypeNotFound:
log.Error("CONNECTION STATUS: Class Type Not Found");
break;
case enuOmniLinkCommStatus.HostNotFound: case enuOmniLinkCommStatus.HostNotFound:
log.Error("CONNECTION STATUS: Host Not Found");
break;
case enuOmniLinkCommStatus.HostNotFoundTryAgain: case enuOmniLinkCommStatus.HostNotFoundTryAgain:
log.Error("CONNECTION STATUS: Host Not Found Try Again");
break;
case enuOmniLinkCommStatus.NonRecoverableError: case enuOmniLinkCommStatus.NonRecoverableError:
log.Error("CONNECTION STATUS: Non Recoverable Error");
break;
case enuOmniLinkCommStatus.NoDataOfRequestedType: case enuOmniLinkCommStatus.NoDataOfRequestedType:
log.Error("CONNECTION STATUS: No Data Of Requested Type"); log.Error("Controller Status: {connectionStatus}", status);
break; break;
default: default:
break; break;
} }
@ -316,7 +219,10 @@ namespace OmniLinkBridge.Modules
if (Controller.Model == MSG.ModelNumber) if (Controller.Model == MSG.ModelNumber)
{ {
Controller.CopySystemInformation(MSG); Controller.CopySystemInformation(MSG);
log.Info("CONTROLLER IS: " + Controller.GetModelText() + " (" + Controller.GetVersionText() + ")");
using (LogContext.PushProperty("Telemetry", "Controller"))
log.Information("Controller is {ControllerModel} firmware {ControllerVersion}",
Controller.GetModelText(), Controller.GetVersionText());
_ = Connected(); _ = Connected();
@ -371,7 +277,7 @@ namespace OmniLinkBridge.Modules
private async Task GetNamed(enuObjectType type) private async Task GetNamed(enuObjectType type)
{ {
log.Debug("Waiting for named units " + type.ToString()); log.Debug("Waiting for named units {unitType}", type.ToString());
GetNextNamed(type, 0); GetNextNamed(type, 0);
@ -415,7 +321,9 @@ namespace OmniLinkBridge.Modules
Controller.TimeFormat = MSG2.Time; Controller.TimeFormat = MSG2.Time;
Controller.TempFormat = MSG2.Temp; Controller.TempFormat = MSG2.Temp;
log.Debug("Temperature format: " + (Controller.TempFormat == enuTempFormat.Fahrenheit ? "Fahrenheit" : "Celsius")); using (LogContext.PushProperty("Telemetry", "TemperatureFormat"))
log.Debug("Temperature format is {TemperatureFormat}",
(Controller.TempFormat == enuTempFormat.Fahrenheit ? "Fahrenheit" : "Celsius"));
nameWait.Set(); nameWait.Set();
break; break;
@ -443,7 +351,8 @@ namespace OmniLinkBridge.Modules
tstats[MSG.ObjectNumber] = DateTime.MinValue; tstats[MSG.ObjectNumber] = DateTime.MinValue;
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus); Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus);
log.Debug("Added thermostat to watch list " + Controller.Thermostats[MSG.ObjectNumber].Name); log.Debug("Added thermostat to watch list {thermostatName}",
Controller.Thermostats[MSG.ObjectNumber].Name);
break; break;
case enuObjectType.Unit: case enuObjectType.Unit:
Controller.Units.CopyProperties(MSG); Controller.Units.CopyProperties(MSG);
@ -471,7 +380,7 @@ namespace OmniLinkBridge.Modules
#region Notifications #region Notifications
private void UnsolicitedNotifications(bool enable) private void UnsolicitedNotifications(bool enable)
{ {
log.Info("Unsolicited notifications " + (enable ? "enabled" : "disabled")); log.Debug("Unsolicited notifications {status}", (enable ? "enabled" : "disabled"));
Controller.Connection.Send(new clsOL2EnableNotifications(Controller.Connection, enable), null); Controller.Connection.Send(new clsOL2EnableNotifications(Controller.Connection, enable), null);
} }
@ -676,7 +585,7 @@ namespace OmniLinkBridge.Modules
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < MSG.MessageLength; i++) for (int i = 0; i < MSG.MessageLength; i++)
sb.Append(MSG.Data[i].ToString() + " "); sb.Append(MSG.Data[i].ToString() + " ");
log.Debug("Unhandled SystemEvent Raw: " + sb.ToString() + "Num: " + MSG.SystemEvent); log.Debug("Unhandled SystemEvent Raw: {raw}, Num: {num}", sb.ToString(), MSG.SystemEvent);
int num = ((int)MSG.MessageLength - 1) / 2; int num = ((int)MSG.MessageLength - 1) / 2;
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
@ -745,7 +654,8 @@ namespace OmniLinkBridge.Modules
}); });
} }
else if (Global.verbose_thermostat_timer) else if (Global.verbose_thermostat_timer)
log.Warn("Ignoring unsolicited unknown temp for Thermostat " + Controller.Thermostats[MSG.ObjectNumber(i)].Name); log.Debug("Ignoring unsolicited unknown temp for Thermostat {thermostatName}",
Controller.Thermostats[MSG.ObjectNumber(i)].Name);
if (!tstats.ContainsKey(MSG.ObjectNumber(i))) if (!tstats.ContainsKey(MSG.ObjectNumber(i)))
tstats.Add(MSG.ObjectNumber(i), DateTime.Now); tstats.Add(MSG.ObjectNumber(i), DateTime.Now);
@ -753,7 +663,8 @@ namespace OmniLinkBridge.Modules
tstats[MSG.ObjectNumber(i)] = DateTime.Now; tstats[MSG.ObjectNumber(i)] = DateTime.Now;
if (Global.verbose_thermostat_timer) if (Global.verbose_thermostat_timer)
log.Debug("Unsolicited status received for Thermostat " + Controller.Thermostats[MSG.ObjectNumber(i)].Name); log.Debug("Unsolicited status received for Thermostat {thermostatName}",
Controller.Thermostats[MSG.ObjectNumber(i)].Name);
} }
} }
break; break;
@ -817,7 +728,8 @@ namespace OmniLinkBridge.Modules
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus); Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus);
if (Global.verbose_thermostat_timer) if (Global.verbose_thermostat_timer)
log.Debug("Polling status for Thermostat " + Controller.Thermostats[tstat.Key].Name); log.Debug("Polling status for Thermostat {thermostatName}",
Controller.Thermostats[tstat.Key].Name);
} }
// Log every minute if update within 5 minutes and connected // Log every minute if update within 5 minutes and connected
@ -836,10 +748,12 @@ namespace OmniLinkBridge.Modules
}); });
} }
else if (Global.verbose_thermostat_timer) else if (Global.verbose_thermostat_timer)
log.Warn("Ignoring unknown temp for Thermostat " + Controller.Thermostats[tstat.Key].Name); log.Warning("Ignoring unknown temp for Thermostat {thermostatName}",
Controller.Thermostats[tstat.Key].Name);
} }
else if (Global.verbose_thermostat_timer) else if (Global.verbose_thermostat_timer)
log.Warn("Not logging out of date status for Thermostat " + Controller.Thermostats[tstat.Key].Name); log.Warning("Not logging out of date status for Thermostat {thermostatName}",
Controller.Thermostats[tstat.Key].Name);
} }
} }
@ -866,7 +780,8 @@ namespace OmniLinkBridge.Modules
tstats[MSG.ObjectNumber(i)] = DateTime.Now; tstats[MSG.ObjectNumber(i)] = DateTime.Now;
if (Global.verbose_thermostat_timer) if (Global.verbose_thermostat_timer)
log.Debug("Polling status received for Thermostat " + Controller.Thermostats[MSG.ObjectNumber(i)].Name); log.Debug("Polling status received for Thermostat {thermostatName}",
Controller.Thermostats[MSG.ObjectNumber(i)].Name);
} }
} }
} }

View file

@ -1,5 +1,5 @@
using HAI_Shared; using HAI_Shared;
using log4net; using Serilog;
using System; using System;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
@ -8,7 +8,7 @@ namespace OmniLinkBridge.Modules
{ {
public class TimeSyncModule : IModule public class TimeSyncModule : IModule
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private OmniLinkII OmniLink { get; set; } private OmniLinkII OmniLink { get; set; }
@ -78,7 +78,7 @@ namespace OmniLinkBridge.Modules
} }
catch catch
{ {
log.Warn("Controller time could not be parsed"); log.Warning("Controller time could not be parsed");
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
@ -91,7 +91,8 @@ namespace OmniLinkBridge.Modules
if (adj > Global.time_drift) if (adj > Global.time_drift)
{ {
log.Warn("Controller time " + time.ToString("MM/dd/yyyy HH:mm:ss") + " out of sync by " + adj + " seconds"); log.Warning("Controller time {controllerTime} out of sync by {driftSeconds} seconds",
time.ToString("MM/dd/yyyy HH:mm:ss"), adj);
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,

View file

@ -1,8 +1,8 @@
using log4net; using Newtonsoft.Json;
using Newtonsoft.Json;
using OmniLinkBridge.Modules; using OmniLinkBridge.Modules;
using OmniLinkBridge.OmniLink; using OmniLinkBridge.OmniLink;
using OmniLinkBridge.WebAPI; using OmniLinkBridge.WebAPI;
using Serilog;
using System; using System;
using System.Reflection; using System.Reflection;
using System.ServiceModel; using System.ServiceModel;
@ -14,7 +14,7 @@ namespace OmniLinkBridge
{ {
public class WebServiceModule : IModule public class WebServiceModule : IModule
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
public static OmniLinkII OmniLink { get; private set; } public static OmniLinkII OmniLink { get; private set; }
@ -43,11 +43,11 @@ namespace OmniLinkBridge
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IOmniLinkService), new WebHttpBinding(), ""); ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IOmniLinkService), new WebHttpBinding(), "");
host.Open(); host.Open();
log.Info("Listening on " + uri.ToString()); log.Information("Listening on {url}", uri.ToString());
} }
catch (CommunicationException ex) catch (CommunicationException ex)
{ {
log.Error("An exception occurred starting web service", ex); log.Error(ex, "An exception occurred starting web service");
host.Abort(); host.Abort();
} }

View file

@ -1,4 +1,5 @@
using log4net; using OmniLinkBridge.Modules;
using Serilog;
using System; using System;
using System.Net; using System.Net;
using System.Net.Mail; using System.Net.Mail;
@ -8,7 +9,7 @@ namespace OmniLinkBridge.Notifications
{ {
public class EmailNotification : INotification public class EmailNotification : INotification
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
public void Notify(string source, string description, NotificationPriority priority) public void Notify(string source, string description, NotificationPriority priority)
{ {
@ -40,7 +41,7 @@ namespace OmniLinkBridge.Notifications
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("An error occurred sending email notification", ex); log.Error(ex, "An error occurred sending email notification");
} }
} }
} }

View file

@ -1,4 +1,4 @@
using log4net; using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -8,7 +8,7 @@ namespace OmniLinkBridge.Notifications
{ {
public static class Notification public static class Notification
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly List<INotification> providers = new List<INotification>() private static readonly List<INotification> providers = new List<INotification>()
{ {
@ -27,7 +27,7 @@ namespace OmniLinkBridge.Notifications
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("Failed to send notification", ex); log.Error(ex, "Failed to send notification");
} }
}); });
} }

View file

@ -1,4 +1,4 @@
using log4net; using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
@ -8,7 +8,7 @@ namespace OmniLinkBridge.Notifications
{ {
public class ProwlNotification : INotification public class ProwlNotification : INotification
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly Uri URI = new Uri("https://api.prowlapp.com/publicapi/add"); private static readonly Uri URI = new Uri("https://api.prowlapp.com/publicapi/add");
@ -37,7 +37,7 @@ namespace OmniLinkBridge.Notifications
private void Client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e) private void Client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{ {
if (e.Error != null) if (e.Error != null)
log.Error("An error occurred sending prowl notification", e.Error); log.Error(e.Error, "An error occurred sending prowl notification");
} }
} }
} }

View file

@ -1,4 +1,4 @@
using log4net; using Serilog;
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Net; using System.Net;
@ -8,7 +8,7 @@ namespace OmniLinkBridge.Notifications
{ {
public class PushoverNotification : INotification public class PushoverNotification : INotification
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly Uri URI = new Uri("https://api.pushover.net/1/messages.json"); private static readonly Uri URI = new Uri("https://api.pushover.net/1/messages.json");
@ -35,7 +35,7 @@ namespace OmniLinkBridge.Notifications
private void Client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e) private void Client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{ {
if (e.Error != null) if (e.Error != null)
log.Error("An error occurred sending pushover notification", e.Error); log.Error(e.Error, "An error occurred sending pushover notification");
} }
} }
} }

View file

@ -161,9 +161,6 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="log4net">
<Version>2.0.8</Version>
</PackageReference>
<PackageReference Include="Mono.Posix-4.5"> <PackageReference Include="Mono.Posix-4.5">
<Version>4.5.0</Version> <Version>4.5.0</Version>
</PackageReference> </PackageReference>
@ -173,6 +170,24 @@
<PackageReference Include="Newtonsoft.Json"> <PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version> <Version>12.0.3</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Serilog">
<Version>2.9.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Formatting.Compact">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Async">
<Version>1.4.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Console">
<Version>3.1.1</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.File">
<Version>4.1.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Http">
<Version>5.2.0</Version>
</PackageReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>
</StartArguments>
</PropertyGroup>
</Project>

View file

@ -1,7 +1,11 @@
using Mono.Unix; using Mono.Unix;
using Serilog;
using Serilog.Events;
using Serilog.Filters;
using Serilog.Formatting.Compact;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Net;
using System.Reflection; using System.Reflection;
using System.ServiceProcess; using System.ServiceProcess;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -12,10 +16,15 @@ namespace OmniLinkBridge
{ {
static CoreServer server; static CoreServer server;
static void Main(string[] args) static int Main(string[] args)
{ {
bool interactive = false; bool interactive = false;
string config_file = "OmniLinkBridge.ini";
string log_file = "log.txt";
bool log_clef = false;
LogEventLevel log_level = LogEventLevel.Information;
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
switch (args[i]) switch (args[i])
@ -24,15 +33,27 @@ namespace OmniLinkBridge
case "-h": case "-h":
case "-help": case "-help":
ShowHelp(); ShowHelp();
return; return 0;
case "-c": case "-c":
Global.config_file = args[++i]; config_file = args[++i];
break; break;
case "-e": case "-e":
Settings.UseEnvironment = true; Global.UseEnvironment = true;
break; break;
case "-d": case "-d":
Settings.ShowDebug = true; Global.DebugSettings = true;
break;
case "-lf":
log_file = args[++i];
if (string.Compare(log_file, "disable", true) == 0)
log_file = null;
break;
case "-lj":
log_clef = true;
break;
case "-ll":
Enum.TryParse(args[++i], out log_level);
break; break;
case "-s": case "-s":
Global.webapi_subscriptions_file = args[++i]; Global.webapi_subscriptions_file = args[++i];
@ -43,27 +64,53 @@ namespace OmniLinkBridge
} }
} }
if (string.IsNullOrEmpty(Global.config_file)) config_file = GetFullPath(config_file);
Global.config_file = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) +
Path.DirectorySeparatorChar + "OmniLinkBridge.ini";
if (string.IsNullOrEmpty(Global.webapi_subscriptions_file)) Global.webapi_subscriptions_file = GetFullPath(Global.webapi_subscriptions_file ?? "WebSubscriptions.json");
Global.webapi_subscriptions_file = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) +
Path.DirectorySeparatorChar + "WebSubscriptions.json";
log4net.Config.XmlConfigurator.Configure(); // Use TLS 1.2 as default connection
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
if(Environment.UserInteractive || interactive) string log_format = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{SourceContext} {Level:u3}] {Message:lj}{NewLine}{Exception}";
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
var log_config = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("Application", "OmniLinkBridge")
.Enrich.WithProperty("Session", Guid.NewGuid())
.Enrich.WithProperty("User", (Environment.UserName + Environment.MachineName).GetHashCode())
.Enrich.FromLogContext();
if (log_file != null)
{
log_file = GetFullPath(log_file);
if (log_clef)
log_config = log_config.WriteTo.Async(a => a.File(new CompactJsonFormatter(), log_file, log_level,
rollingInterval: RollingInterval.Day, retainedFileCountLimit: 15));
else
log_config = log_config.WriteTo.Async(a => a.File(log_file, log_level, log_format,
rollingInterval: RollingInterval.Day, retainedFileCountLimit: 15));
}
if (UseTelemetry())
log_config = log_config.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(Matching.WithProperty("Telemetry"))
.WriteTo.Http("https://telemetry.excalibur-partners.com"));
if (Environment.UserInteractive || interactive)
log_config = log_config.WriteTo.Console(outputTemplate: log_format);
Log.Logger = log_config.CreateLogger();
try try
{ {
Settings.LoadSettings(Global.config_file); Settings.LoadSettings(config_file);
} }
catch catch
{ {
// Errors are logged in LoadSettings(); // Errors are logged in LoadSettings();
Environment.Exit(1); Log.CloseAndFlush();
return -1;
} }
if (Environment.UserInteractive || interactive) if (Environment.UserInteractive || interactive)
@ -104,6 +151,16 @@ namespace OmniLinkBridge
ServiceBase.Run(ServicesToRun); ServiceBase.Run(ServicesToRun);
} }
return 0;
}
static string GetFullPath(string file)
{
if (Path.IsPathRooted(file))
return file;
return Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), file);
} }
protected static void myHandler(object sender, ConsoleCancelEventArgs args) protected static void myHandler(object sender, ConsoleCancelEventArgs args)
@ -117,16 +174,28 @@ namespace OmniLinkBridge
return Type.GetType("Mono.Runtime") != null; return Type.GetType("Mono.Runtime") != null;
} }
static bool UseTelemetry()
{
return string.Compare(Environment.GetEnvironmentVariable("TELEMETRY_OPTOUT"), "1") != 0;
}
static void ShowHelp() static void ShowHelp()
{ {
Console.WriteLine( Console.WriteLine(
AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-e] [-d] [-s subscriptions_file] [-i]\n" + AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-e] [-d] [-j] [-s subscriptions_file]\n" +
"\t[-debug-config] [-ignore-env]\n" + "\t[-lf log_file|disable] [-lj [-ll verbose|debug|information|warning|error] [-i]\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-e Check environment variables for configuration settings\n" +
"\t-d Show debug output for configuration loading\n" + "\t-d Show debug ouput 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-lf Specifies the rolling log file. Retention is 15 days. Default is log.txt.\n" +
"\t-lj Write logs as CLEF (compact log event format) JSON.\n" +
"\t-ll Minimum level at which events will be logged. Default is information.\n" +
"\t-i Run in interactive mode");
Console.WriteLine(
"\nOmniLink Bridge collects anonymous telemetry data to help improve the software.\n" +
"You can opt of telemetry by setting a TELEMETRY_OPTOUT environment variable to 1.");
} }
} }
} }

View file

@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("OmniLinkBridge")] [assembly: AssemblyTitle("OmniLink Bridge")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Excalibur Partners, LLC")] [assembly: AssemblyCompany("Excalibur Partners, LLC")]
[assembly: AssemblyProduct("OmniLinkBridge")] [assembly: AssemblyProduct("OmniLinkBridge")]
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2019")] [assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2020")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]

View file

@ -1,4 +1,4 @@
using log4net; using Serilog;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -7,14 +7,13 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net.Mail; using System.Net.Mail;
using System.Reflection; using System.Reflection;
using System.Threading;
namespace OmniLinkBridge namespace OmniLinkBridge
{ {
public static class Settings public static class Settings
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
public static bool ShowDebug { get; set; }
public static bool UseEnvironment { get; set; }
public static void LoadSettings(string file) public static void LoadSettings(string file)
{ {
@ -115,10 +114,10 @@ namespace OmniLinkBridge
private static string CheckEnv(this NameValueCollection settings, string name) private static string CheckEnv(this NameValueCollection settings, string name)
{ {
string env = UseEnvironment ? Environment.GetEnvironmentVariable(name.ToUpper()) : null; string env = Global.UseEnvironment ? Environment.GetEnvironmentVariable(name.ToUpper()) : null;
string value = !string.IsNullOrEmpty(env) ? env : settings[name]; string value = !string.IsNullOrEmpty(env) ? env : settings[name];
if (ShowDebug) if (Global.DebugSettings)
log.Debug((!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(5) + $"{name}: {value}"); log.Debug((!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(5) + $"{name}: {value}");
return value; return value;
@ -170,7 +169,7 @@ namespace OmniLinkBridge
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("Invalid override zone specified for " + section, ex); log.Error(ex, "Invalid override zone specified for {section}", section);
throw; throw;
} }
} }
@ -181,7 +180,7 @@ namespace OmniLinkBridge
if(string.IsNullOrEmpty(value)) if(string.IsNullOrEmpty(value))
{ {
log.Error("Empty string specified for " + section); log.Error("Empty string specified for {section}", section);
throw new Exception(); throw new Exception();
} }
@ -196,7 +195,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid integer specified for " + section); log.Error("Invalid integer specified for {section}", section);
throw; throw;
} }
} }
@ -214,7 +213,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid range specified for " + section); log.Error("Invalid range specified for {section}", section);
throw; throw;
} }
} }
@ -232,7 +231,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid port specified for " + section); log.Error("Invalid port specified for {section}", section);
throw; throw;
} }
} }
@ -245,7 +244,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid email specified for " + section); log.Error("Invalid email specified for {section}", section);
throw; throw;
} }
} }
@ -269,7 +268,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid email specified for " + section); log.Error("Invalid email specified for {section}", section);
throw; throw;
} }
} }
@ -285,7 +284,7 @@ namespace OmniLinkBridge
} }
catch catch
{ {
log.Error("Invalid string specified for " + section); log.Error("Invalid string specified for {section}", section);
throw; throw;
} }
} }
@ -302,7 +301,7 @@ namespace OmniLinkBridge
return false; return false;
else else
{ {
log.Error("Invalid yes/no or true/false specified for " + section); log.Error("Invalid yes/no or true/false specified for {section}", section);
throw new Exception(); throw new Exception();
} }
} }
@ -330,24 +329,24 @@ namespace OmniLinkBridge
return settings; return settings;
} }
private static NameValueCollection LoadCollection(string sFile) private static NameValueCollection LoadCollection(string file)
{ {
if (ShowDebug) if (Global.DebugSettings)
log.Debug($"Using settings file {sFile}"); log.Debug("Using settings file {file}", file);
if(!File.Exists(sFile)) if(!File.Exists(file))
{ {
log.Warn($"Unable to locate settings file {sFile}"); log.Warning("Unable to locate settings file {file}", file);
return new NameValueCollection(); return new NameValueCollection();
} }
try try
{ {
return LoadCollection(File.ReadAllLines(sFile)); return LoadCollection(File.ReadAllLines(file));
} }
catch (FileNotFoundException ex) catch (FileNotFoundException ex)
{ {
log.Error("Error parsing settings file " + sFile, ex); log.Error(ex, "Error parsing settings file {file}", file);
throw; throw;
} }
} }

View file

@ -1,6 +1,6 @@
using HAI_Shared; using HAI_Shared;
using log4net;
using OmniLinkBridge.WebAPI; using OmniLinkBridge.WebAPI;
using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -12,7 +12,7 @@ namespace OmniLinkBridge.WebAPI
[ServiceBehavior(IncludeExceptionDetailInFaults = true)] [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class OmniLinkService : IOmniLinkService public class OmniLinkService : IOmniLinkService
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
public void Subscribe(SubscribeContract contract) public void Subscribe(SubscribeContract contract)
{ {
@ -39,7 +39,7 @@ namespace OmniLinkBridge.WebAPI
public AreaContract GetArea(ushort id) public AreaContract GetArea(ushort id)
{ {
log.Debug("GetArea: " + id); log.Debug("GetArea: {id}", id);
WebOperationContext ctx = WebOperationContext.Current; WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("type", "area"); ctx.OutgoingResponse.Headers.Add("type", "area");
@ -139,7 +139,7 @@ namespace OmniLinkBridge.WebAPI
public ZoneContract GetZone(ushort id) public ZoneContract GetZone(ushort id)
{ {
log.Debug("GetZone: " + id); log.Debug("GetZone: {id}", id);
WebOperationContext ctx = WebOperationContext.Current; WebOperationContext ctx = WebOperationContext.Current;
@ -173,7 +173,7 @@ namespace OmniLinkBridge.WebAPI
public UnitContract GetUnit(ushort id) public UnitContract GetUnit(ushort id)
{ {
log.Debug("GetUnit: " + id); log.Debug("GetUnit: {id}", id);
WebOperationContext ctx = WebOperationContext.Current; WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("type", "unit"); ctx.OutgoingResponse.Headers.Add("type", "unit");
@ -183,7 +183,7 @@ namespace OmniLinkBridge.WebAPI
public void SetUnit(CommandContract unit) public void SetUnit(CommandContract unit)
{ {
log.Debug("SetUnit: " + unit.id + " to " + unit.value + "%"); log.Debug("SetUnit: {id} to {value}%", unit.id, unit.value);
if (unit.value == 0) if (unit.value == 0)
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Off, 0, unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Off, 0, unit.id);
@ -196,7 +196,7 @@ namespace OmniLinkBridge.WebAPI
public void SetUnitKeypadPress(CommandContract unit) public void SetUnitKeypadPress(CommandContract unit)
{ {
log.Debug("SetUnitKeypadPress: " + unit.id + " to " + unit.value + " button"); log.Debug("SetUnitKeypadPress: {id} to {value}", unit.id, unit.value);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.LutronHomeWorksKeypadButtonPress, BitConverter.GetBytes(unit.value)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.LutronHomeWorksKeypadButtonPress, BitConverter.GetBytes(unit.value)[0], unit.id);
} }
@ -217,7 +217,7 @@ namespace OmniLinkBridge.WebAPI
public ThermostatContract GetThermostat(ushort id) public ThermostatContract GetThermostat(ushort id)
{ {
log.Debug("GetThermostat: " + id); log.Debug("GetThermostat: {id}", id);
WebOperationContext ctx = WebOperationContext.Current; WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("type", "thermostat"); ctx.OutgoingResponse.Headers.Add("type", "thermostat");
@ -236,7 +236,7 @@ namespace OmniLinkBridge.WebAPI
} }
int temp = tempHigh.ToOmniTemp(); int temp = tempHigh.ToOmniTemp();
log.Debug("SetThermostatCoolSetpoint: " + unit.id + " to " + unit.value + tempUnit + "(" + temp + ")"); log.Debug("SetThermostatCoolSetpoint: {id} to {value}{tempUnit} {temp}", unit.id, unit.value, tempUnit, temp);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.SetHighSetPt, BitConverter.GetBytes(temp)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.SetHighSetPt, BitConverter.GetBytes(temp)[0], unit.id);
} }
@ -251,25 +251,25 @@ namespace OmniLinkBridge.WebAPI
} }
int temp = tempLoad.ToOmniTemp(); int temp = tempLoad.ToOmniTemp();
log.Debug("SetThermostatHeatSetpoint: " + unit.id + " to " + unit.value + tempUnit + "(" + temp + ")"); log.Debug("SetThermostatHeatSetpoint: {id} to {value}{tempUnit} {temp}", unit.id, unit.value, tempUnit, temp);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.SetLowSetPt, BitConverter.GetBytes(temp)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.SetLowSetPt, BitConverter.GetBytes(temp)[0], unit.id);
} }
public void SetThermostatMode(CommandContract unit) public void SetThermostatMode(CommandContract unit)
{ {
log.Debug("SetThermostatMode: " + unit.id + " to " + unit.value); log.Debug("SetThermostatMode: {id} to {value}", unit.id, unit.value);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Mode, BitConverter.GetBytes(unit.value)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Mode, BitConverter.GetBytes(unit.value)[0], unit.id);
} }
public void SetThermostatFanMode(CommandContract unit) public void SetThermostatFanMode(CommandContract unit)
{ {
log.Debug("SetThermostatFanMode: " + unit.id + " to " + unit.value); log.Debug("SetThermostatFanMode: {id} to {value}", unit.id, unit.value);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Fan, BitConverter.GetBytes(unit.value)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Fan, BitConverter.GetBytes(unit.value)[0], unit.id);
} }
public void SetThermostatHold(CommandContract unit) public void SetThermostatHold(CommandContract unit)
{ {
log.Debug("SetThermostatHold: " + unit.id + " to " + unit.value); log.Debug("SetThermostatHold: {id} to {value}", unit.id, unit.value);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Hold, BitConverter.GetBytes(unit.value)[0], unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Hold, BitConverter.GetBytes(unit.value)[0], unit.id);
} }
@ -290,7 +290,7 @@ namespace OmniLinkBridge.WebAPI
public void PushButton(CommandContract unit) public void PushButton(CommandContract unit)
{ {
log.Debug("PushButton: " + unit.id); log.Debug("PushButton: {id}", unit.id);
WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Button, 0, unit.id); WebServiceModule.OmniLink.Controller.SendCommand(enuUnitCommand.Button, 0, unit.id);
} }
} }

View file

@ -1,5 +1,5 @@
using log4net; using Newtonsoft.Json;
using Newtonsoft.Json; using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -10,7 +10,7 @@ namespace OmniLinkBridge.WebAPI
{ {
static class WebNotification static class WebNotification
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
private static List<string> subscriptions = new List<string>(); private static List<string> subscriptions = new List<string>();
private static readonly object subscriptions_lock = new object(); private static readonly object subscriptions_lock = new object();
@ -52,7 +52,7 @@ namespace OmniLinkBridge.WebAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("An error occurred sending notification to " + subscription, ex); log.Error(ex, "An error occurred sending notification to {client}", subscription);
subscriptions.Remove(subscription); subscriptions.Remove(subscription);
SaveSubscriptions(); SaveSubscriptions();
} }
@ -63,7 +63,7 @@ namespace OmniLinkBridge.WebAPI
{ {
if (e.Error != null) if (e.Error != null)
{ {
log.Error("An error occurred sending notification to " + e.UserState.ToString(), e.Error); log.Error(e.Error, "An error occurred sending notification to {client}", e.UserState.ToString());
lock (subscriptions_lock) lock (subscriptions_lock)
subscriptions.Remove(e.UserState.ToString()); subscriptions.Remove(e.UserState.ToString());
@ -88,7 +88,7 @@ namespace OmniLinkBridge.WebAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("An error occurred restoring subscriptions", ex); log.Error(ex, "An error occurred restoring subscriptions");
} }
} }
@ -107,7 +107,7 @@ namespace OmniLinkBridge.WebAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Error("An error occurred saving subscriptions", ex); log.Error(ex, "An error occurred saving subscriptions");
} }
} }
} }

View file

@ -2,12 +2,12 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
[assembly: AssemblyTitle("OmniLinkBridgeTest")] [assembly: AssemblyTitle("OmniLink Bridge Test")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Excalibur Partners, LLC")] [assembly: AssemblyCompany("Excalibur Partners, LLC")]
[assembly: AssemblyProduct("OmniLinkBridgeTest")] [assembly: AssemblyProduct("OmniLinkBridgeTest")]
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2019")] [assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2020")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]

View file

@ -9,7 +9,7 @@ You can use docker to build an image from git or download the [binary here](http
- .NET Framework 4.5.2 (or Mono equivalent) - .NET Framework 4.5.2 (or Mono equivalent)
## Operation ## Operation
OmniLinkBridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](https://github.com/excaliburpartners/OmniLinkBridge/blob/master/OmniLinkBridge/OmniLinkBridge.ini) for specifics. OmniLink Bridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](https://github.com/excaliburpartners/OmniLinkBridge/blob/master/OmniLinkBridge/OmniLinkBridge.ini) for specifics.
- OmniLinkII: controller_ - OmniLinkII: controller_
- Maintains connection to the OmniLink controller - Maintains connection to the OmniLink controller
@ -330,3 +330,6 @@ Configure mysql_connection in OmniLinkBridge.ini. For Windows change DRIVER={MyS
``` ```
mysql_connection = DRIVER={MySQL};SERVER=localhost;DATABASE=OmniLinkBridge;USER=root;PASSWORD=myPassword;OPTION=3; mysql_connection = DRIVER={MySQL};SERVER=localhost;DATABASE=OmniLinkBridge;USER=root;PASSWORD=myPassword;OPTION=3;
``` ```
## Telemetry
OmniLink Bridge collects anonymous telemetry data to help improve the software. You can opt of telemetry by setting a TELEMETRY_OPTOUT environment variable to 1.