2016-11-15 17:37:56 +00:00
|
|
|
|
using HAI_Shared;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Data.Odbc;
|
|
|
|
|
using System.IO;
|
2016-11-21 02:31:27 +00:00
|
|
|
|
using System.Reflection;
|
2016-11-15 17:37:56 +00:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
namespace HAILogger
|
|
|
|
|
{
|
|
|
|
|
class CoreServer
|
|
|
|
|
{
|
|
|
|
|
private bool quitting = false;
|
|
|
|
|
private bool terminate = false;
|
|
|
|
|
|
|
|
|
|
// HAI Controller
|
|
|
|
|
private clsHAC HAC = null;
|
|
|
|
|
private DateTime retry = DateTime.MinValue;
|
|
|
|
|
private List<string> alarms = new List<string>();
|
|
|
|
|
|
|
|
|
|
// Thermostats
|
|
|
|
|
private Dictionary<ushort, DateTime> tstats = new Dictionary<ushort, DateTime>();
|
|
|
|
|
private System.Timers.Timer tstat_timer = new System.Timers.Timer();
|
|
|
|
|
private object tstat_lock = new object();
|
|
|
|
|
|
|
|
|
|
// Time Sync
|
|
|
|
|
private System.Timers.Timer tsync_timer = new System.Timers.Timer();
|
|
|
|
|
private DateTime tsync_check = DateTime.MinValue;
|
|
|
|
|
|
|
|
|
|
// mySQL Database
|
|
|
|
|
private OdbcConnection mysql_conn = null;
|
|
|
|
|
private DateTime mysql_retry = DateTime.MinValue;
|
|
|
|
|
private OdbcCommand mysql_command = null;
|
|
|
|
|
private Queue<string> mysql_queue = new Queue<string>();
|
|
|
|
|
private object mysql_lock = new object();
|
|
|
|
|
|
|
|
|
|
public CoreServer()
|
|
|
|
|
{
|
|
|
|
|
Thread handler = new Thread(Server);
|
|
|
|
|
handler.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Server()
|
|
|
|
|
{
|
|
|
|
|
Global.event_log = "EventLog.txt";
|
|
|
|
|
Global.event_source = "HAI Logger";
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(Global.dir_config))
|
2016-11-21 02:31:27 +00:00
|
|
|
|
Global.dir_config = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
2016-11-15 17:37:56 +00:00
|
|
|
|
|
|
|
|
|
Settings.LoadSettings();
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
Event.WriteInfo("CoreServer", "Starting up server " +
|
|
|
|
|
Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
2016-11-15 17:37:56 +00:00
|
|
|
|
|
|
|
|
|
tstat_timer.Elapsed += tstat_timer_Elapsed;
|
|
|
|
|
tstat_timer.AutoReset = false;
|
|
|
|
|
|
|
|
|
|
tsync_timer.Elapsed += tsync_timer_Elapsed;
|
|
|
|
|
tsync_timer.AutoReset = false;
|
|
|
|
|
|
|
|
|
|
if (Global.mysql_logging)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteInfo("DatabaseLogger", "Connecting to database");
|
|
|
|
|
|
|
|
|
|
mysql_conn = new OdbcConnection(Global.mysql_connection);
|
|
|
|
|
|
|
|
|
|
// Must make an initial connection
|
|
|
|
|
if (!DBOpen())
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAC = new clsHAC();
|
|
|
|
|
|
|
|
|
|
WebService web = new WebService(HAC);
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.webapi_enabled)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
web.Start();
|
|
|
|
|
|
|
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
// End gracefully when not logging or database queue empty
|
|
|
|
|
if (quitting && (!Global.mysql_logging || DBQueueCount() == 0))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// Make sure controller connection is active
|
|
|
|
|
if (HAC.Connection.ConnectionState == enuOmniLinkConnectionState.Offline &&
|
|
|
|
|
retry < DateTime.Now)
|
|
|
|
|
{
|
|
|
|
|
Connect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure database connection is active
|
|
|
|
|
if (Global.mysql_logging && mysql_conn.State != ConnectionState.Open)
|
|
|
|
|
{
|
|
|
|
|
// Nothing we can do if shutting down
|
|
|
|
|
if (quitting)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (mysql_retry < DateTime.Now)
|
|
|
|
|
DBOpen();
|
|
|
|
|
|
|
|
|
|
if (mysql_conn.State != ConnectionState.Open)
|
|
|
|
|
{
|
|
|
|
|
// Loop to prevent database queries from executing
|
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sleep when not logging or database queue empty
|
|
|
|
|
if (!Global.mysql_logging || DBQueueCount() == 0)
|
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grab a copy in case the database query fails
|
|
|
|
|
string query;
|
|
|
|
|
lock (mysql_lock)
|
|
|
|
|
query = mysql_queue.Peek();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Execute the database query
|
|
|
|
|
mysql_command = new OdbcCommand(query, mysql_conn);
|
|
|
|
|
mysql_command.ExecuteNonQuery();
|
|
|
|
|
|
|
|
|
|
// Successful remove query from queue
|
|
|
|
|
lock (mysql_lock)
|
|
|
|
|
mysql_queue.Dequeue();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
if (mysql_conn.State != ConnectionState.Open)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteWarn("DatabaseLogger", "Lost connection to database");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Event.WriteError("DatabaseLogger", "Error executing query\r\n" + ex.Message + "\r\n" + query);
|
|
|
|
|
|
|
|
|
|
// Prevent an endless loop from failed query
|
|
|
|
|
lock (mysql_lock)
|
|
|
|
|
mysql_queue.Dequeue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Event.WriteInfo("CoreServer", "Shutting down server");
|
|
|
|
|
|
|
|
|
|
if (Global.webapi_enabled)
|
|
|
|
|
web.Stop();
|
|
|
|
|
|
|
|
|
|
Disconnect();
|
|
|
|
|
HAC = null;
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.mysql_logging)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
DBClose();
|
|
|
|
|
|
|
|
|
|
terminate = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Connected()
|
|
|
|
|
{
|
|
|
|
|
retry = DateTime.MinValue;
|
|
|
|
|
|
|
|
|
|
GetNamedProperties();
|
|
|
|
|
UnsolicitedNotifications(true);
|
|
|
|
|
|
|
|
|
|
tstat_timer.Interval = ThermostatTimerInterval();
|
|
|
|
|
tstat_timer.Start();
|
|
|
|
|
|
|
|
|
|
if (Global.hai_time_sync)
|
|
|
|
|
{
|
|
|
|
|
tsync_check = DateTime.MinValue;
|
|
|
|
|
|
|
|
|
|
tsync_timer.Interval = TimeTimerInterval();
|
|
|
|
|
tsync_timer.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Shutdown()
|
|
|
|
|
{
|
|
|
|
|
quitting = true;
|
|
|
|
|
|
|
|
|
|
while (!terminate)
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
|
|
|
|
|
Event.WriteInfo("CoreServer", "Shutdown completed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Connection
|
|
|
|
|
private void Connect()
|
|
|
|
|
{
|
|
|
|
|
if (HAC.Connection.ConnectionState == enuOmniLinkConnectionState.Offline)
|
|
|
|
|
{
|
|
|
|
|
retry = DateTime.Now.AddMinutes(1);
|
|
|
|
|
|
|
|
|
|
HAC.Connection.NetworkAddress = Global.hai_address;
|
|
|
|
|
HAC.Connection.NetworkPort = (ushort)Global.hai_port;
|
|
|
|
|
HAC.Connection.ControllerKey = clsUtil.HexString2ByteArray(
|
|
|
|
|
String.Concat(Global.hai_key1, Global.hai_key2));
|
|
|
|
|
|
|
|
|
|
HAC.PreferredNetworkProtocol = clsHAC.enuPreferredNetworkProtocol.TCP;
|
|
|
|
|
HAC.Connection.ConnectionType = enuOmniLinkConnectionType.Network_TCP;
|
|
|
|
|
|
|
|
|
|
HAC.Connection.Connect(HandleConnectStatus, HandleUnsolicitedPackets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Disconnect()
|
|
|
|
|
{
|
|
|
|
|
if (HAC.Connection.ConnectionState != enuOmniLinkConnectionState.Offline)
|
|
|
|
|
HAC.Connection.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleConnectStatus(enuOmniLinkCommStatus CS)
|
|
|
|
|
{
|
|
|
|
|
switch (CS)
|
|
|
|
|
{
|
|
|
|
|
case enuOmniLinkCommStatus.NoReply:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: No Reply");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnrecognizedReply:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unrecognized Reply");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnsupportedProtocol:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unsupported Protocol");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ClientSessionTerminated:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Client Session Terminated");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ControllerSessionTerminated:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Controller Session Terminated");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.CannotStartNewSession:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Cannot Start New Session");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.LoginFailed:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Login Failed");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnableToOpenSocket:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unable To Open Socket");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnableToConnect:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unable To Connect");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.SocketClosed:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Socket Closed");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnexpectedError:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unexpected Error");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnableToCreateSocket:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unable To Create Socket");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.Retrying:
|
|
|
|
|
Event.WriteWarn("CoreServer", "CONNECTION STATUS: Retrying");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.Connected:
|
|
|
|
|
IdentifyController();
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.Connecting:
|
|
|
|
|
Event.WriteInfo("CoreServer", "CONNECTION STATUS: Connecting");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.Disconnected:
|
|
|
|
|
Event.WriteInfo("CoreServer", "CONNECTION STATUS: Disconnected");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.InterruptedFunctionCall:
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (!quitting)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Interrupted Function Call");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.PermissionDenied:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Permission Denied");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.BadAddress:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Bad Address");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.InvalidArgument:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Invalid Argument");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.TooManyOpenFiles:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Too Many Open Files");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ResourceTemporarilyUnavailable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Resource Temporarily Unavailable");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.OperationNowInProgress:
|
|
|
|
|
Event.WriteWarn("CoreServer", "CONNECTION STATUS: Operation Now In Progress");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.OperationAlreadyInProgress:
|
|
|
|
|
Event.WriteWarn("CoreServer", "CONNECTION STATUS: Operation Already In Progress");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.SocketOperationOnNonSocket:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Socket Operation On Non Socket");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.DestinationAddressRequired:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Destination Address Required");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.MessgeTooLong:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Message Too Long");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.WrongProtocolType:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Wrong Protocol Type");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.BadProtocolOption:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Bad Protocol Option");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ProtocolNotSupported:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Protocol Not Supported");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.SocketTypeNotSupported:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Socket Type Not Supported");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.OperationNotSupported:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Operation Not Supported");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ProtocolFamilyNotSupported:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Protocol Family Not Supported");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.AddressFamilyNotSupported:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Address Family Not Supported");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.AddressInUse:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Address In Use");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.AddressNotAvailable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Address Not Available");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NetworkIsDown:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Network Is Down");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NetworkIsUnreachable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Network Is Unreachable");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NetworkReset:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Network Reset");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ConnectionAborted:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Connection Aborted");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ConnectionResetByPeer:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Connection Reset By Peer");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NoBufferSpaceAvailable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: No Buffer Space Available");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.AlreadyConnected:
|
|
|
|
|
Event.WriteWarn("CoreServer", "CONNECTION STATUS: Already Connected");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NotConnected:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Not Connected");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.CannotSendAfterShutdown:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Cannot Send After Shutdown");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ConnectionTimedOut:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Connection Timed Out");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ConnectionRefused:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Connection Refused");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.HostIsDown:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Host Is Down");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.HostUnreachable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Host Unreachable");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.TooManyProcesses:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Too Many Processes");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NetworkSubsystemIsUnavailable:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Network Subsystem Is Unavailable");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.UnsupportedVersion:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Unsupported Version");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NotInitialized:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Not Initialized");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ShutdownInProgress:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Shutdown In Progress");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.ClassTypeNotFound:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Class Type Not Found");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.HostNotFound:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Host Not Found");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.HostNotFoundTryAgain:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Host Not Found Try Again");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NonRecoverableError:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: Non Recoverable Error");
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLinkCommStatus.NoDataOfRequestedType:
|
|
|
|
|
Event.WriteError("CoreServer", "CONNECTION STATUS: No Data Of Requested Type");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void IdentifyController()
|
|
|
|
|
{
|
|
|
|
|
if (HAC.Connection.ConnectionState == enuOmniLinkConnectionState.Online ||
|
|
|
|
|
HAC.Connection.ConnectionState == enuOmniLinkConnectionState.OnlineSecure)
|
|
|
|
|
{
|
|
|
|
|
HAC.Connection.Send(new clsOL2MsgRequestSystemInformation(HAC.Connection), HandleIdentifyController);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleIdentifyController(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((B.Length > 3) && (B[2] == (byte)enuOmniLink2MessageType.SystemInformation))
|
|
|
|
|
{
|
|
|
|
|
clsOL2MsgSystemInformation MSG = new clsOL2MsgSystemInformation(HAC.Connection, B);
|
|
|
|
|
if (HAC.Model == MSG.ModelNumber)
|
|
|
|
|
{
|
|
|
|
|
HAC.CopySystemInformation(MSG);
|
|
|
|
|
Event.WriteInfo("CoreServer", "CONTROLLER IS: " + HAC.GetModelText() + " (" + HAC.GetVersionText() + ")");
|
|
|
|
|
|
|
|
|
|
Connected();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Event.WriteError("CoreServer", "Model does not match file");
|
|
|
|
|
HAC.Connection.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Names
|
|
|
|
|
private void GetNamedProperties()
|
|
|
|
|
{
|
|
|
|
|
Event.WriteInfo("CoreServer", "Retrieving named units");
|
|
|
|
|
|
|
|
|
|
GetNextNamed(enuObjectType.Area, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
GetNextNamed(enuObjectType.Zone, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
GetNextNamed(enuObjectType.Thermostat, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
GetNextNamed(enuObjectType.Unit, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
GetNextNamed(enuObjectType.Message, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
GetNextNamed(enuObjectType.Button, 0);
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void GetNextNamed(enuObjectType type, int ix)
|
|
|
|
|
{
|
|
|
|
|
clsOL2MsgRequestProperties MSG = new clsOL2MsgRequestProperties(HAC.Connection);
|
|
|
|
|
MSG.ObjectType = type;
|
|
|
|
|
MSG.IndexNumber = (UInt16)ix;
|
|
|
|
|
MSG.RelativeDirection = 1; // next object after IndexNumber
|
|
|
|
|
MSG.Filter1 = 1; // (0=Named or Unnamed, 1=Named, 2=Unnamed).
|
|
|
|
|
MSG.Filter2 = 0; // Any Area
|
|
|
|
|
MSG.Filter3 = 0; // Any Room
|
|
|
|
|
HAC.Connection.Send(MSG, HandleNamedPropertiesResponse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleNamedPropertiesResponse(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// does it look like a valid response
|
|
|
|
|
if ((B.Length > 3) && (B[0] == 0x21))
|
|
|
|
|
{
|
|
|
|
|
switch ((enuOmniLink2MessageType)B[2])
|
|
|
|
|
{
|
|
|
|
|
case enuOmniLink2MessageType.EOD:
|
2016-11-21 02:31:27 +00:00
|
|
|
|
|
2016-11-15 17:37:56 +00:00
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Properties:
|
|
|
|
|
|
|
|
|
|
clsOL2MsgProperties MSG = new clsOL2MsgProperties(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
switch (MSG.ObjectType)
|
|
|
|
|
{
|
|
|
|
|
case enuObjectType.Area:
|
|
|
|
|
HAC.Areas.CopyProperties(MSG);
|
2016-11-21 02:31:27 +00:00
|
|
|
|
break;
|
2016-11-15 17:37:56 +00:00
|
|
|
|
case enuObjectType.Zone:
|
|
|
|
|
HAC.Zones.CopyProperties(MSG);
|
2016-11-21 02:31:27 +00:00
|
|
|
|
|
|
|
|
|
if (HAC.Zones[MSG.ObjectNumber].IsTemperatureZone())
|
|
|
|
|
HAC.Connection.Send(new clsOL2MsgRequestExtendedStatus(HAC.Connection, enuObjectType.Auxillary, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestAuxillaryStatus);
|
|
|
|
|
|
2016-11-15 17:37:56 +00:00
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Thermostat:
|
|
|
|
|
HAC.Thermostats.CopyProperties(MSG);
|
|
|
|
|
|
|
|
|
|
if (!tstats.ContainsKey(MSG.ObjectNumber))
|
|
|
|
|
tstats.Add(MSG.ObjectNumber, DateTime.MinValue);
|
|
|
|
|
else
|
|
|
|
|
tstats[MSG.ObjectNumber] = DateTime.MinValue;
|
|
|
|
|
|
|
|
|
|
HAC.Connection.Send(new clsOL2MsgRequestExtendedStatus(HAC.Connection, enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus);
|
|
|
|
|
Event.WriteVerbose("ThermostatTimer", "Added to watch list " + HAC.Thermostats[MSG.ObjectNumber].Name);
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Unit:
|
|
|
|
|
HAC.Units.CopyProperties(MSG);
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Message:
|
|
|
|
|
HAC.Messages.CopyProperties(MSG);
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Button:
|
|
|
|
|
HAC.Buttons.CopyProperties(MSG);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GetNextNamed(MSG.ObjectType, MSG.ObjectNumber);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Notifications
|
|
|
|
|
private void UnsolicitedNotifications(bool enable)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteInfo("CoreServer", "Unsolicited notifications " + (enable ? "enabled" : "disabled"));
|
|
|
|
|
HAC.Connection.Send(new clsOL2EnableNotifications(HAC.Connection, enable), null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool HandleUnsolicitedPackets(byte[] B)
|
|
|
|
|
{
|
|
|
|
|
if ((B.Length > 3) && (B[0] == 0x21))
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
|
|
|
|
|
switch ((enuOmniLink2MessageType)B[2])
|
|
|
|
|
{
|
|
|
|
|
case enuOmniLink2MessageType.ClearNames:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.DownloadNames:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.UploadNames:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.NameData:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ClearVoices:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.DownloadVoices:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.UploadVoices:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.VoiceData:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Command:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.EnableNotifications:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemInformation:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemStatus:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemTroubles:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemFeatures:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Capacities:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Properties:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Status:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.EventLogItem:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ValidateCode:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemFormats:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Login:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.Logout:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ActivateKeypadEmg:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ExtSecurityStatus:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.CmdExtSecurity:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.AudioSourceStatus:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.SystemEvents:
|
|
|
|
|
HandleUnsolicitedSystemEvent(B);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ZoneReadyStatus:
|
|
|
|
|
break;
|
|
|
|
|
case enuOmniLink2MessageType.ExtendedStatus:
|
|
|
|
|
HandleUnsolicitedExtendedStatus(B);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_unhandled && !handled)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteVerbose("CoreServer", "Unhandled notification: " + ((enuOmniLink2MessageType)B[2]).ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleUnsolicitedSystemEvent(byte[] B)
|
|
|
|
|
{
|
|
|
|
|
clsOL2SystemEvent MSG = new clsOL2SystemEvent(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
enuEventType type;
|
|
|
|
|
string value = string.Empty;
|
|
|
|
|
bool alert = false;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent >= 1 && MSG.SystemEvent <= 255)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.USER_MACRO_BUTTON;
|
|
|
|
|
value = ((int)MSG.SystemEvent).ToString() + " " + HAC.Buttons[MSG.SystemEvent].Name;
|
2016-11-21 02:31:27 +00:00
|
|
|
|
|
2016-11-15 17:37:56 +00:00
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 768 && MSG.SystemEvent <= 771)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.PHONE_;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent == 768)
|
|
|
|
|
{
|
|
|
|
|
value = "DEAD";
|
|
|
|
|
alert = true;
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent == 769)
|
|
|
|
|
value = "RING";
|
|
|
|
|
else if (MSG.SystemEvent == 770)
|
|
|
|
|
value = "OFF HOOK";
|
|
|
|
|
else if (MSG.SystemEvent == 771)
|
|
|
|
|
value = "ON HOOK";
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 772 && MSG.SystemEvent <= 773)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.AC_POWER_;
|
|
|
|
|
alert = true;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent == 772)
|
|
|
|
|
value = "OFF";
|
|
|
|
|
else if (MSG.SystemEvent == 773)
|
|
|
|
|
value = "RESTORED";
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 774 && MSG.SystemEvent <= 775)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.BATTERY_;
|
|
|
|
|
alert = true;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent == 774)
|
|
|
|
|
value = "LOW";
|
|
|
|
|
else if (MSG.SystemEvent == 775)
|
|
|
|
|
value = "OK";
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 776 && MSG.SystemEvent <= 777)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.DCM_;
|
|
|
|
|
alert = true;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent == 776)
|
|
|
|
|
value = "TROUBLE";
|
|
|
|
|
else if (MSG.SystemEvent == 777)
|
|
|
|
|
value = "OK";
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 778 && MSG.SystemEvent <= 781)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.ENERGY_COST_;
|
|
|
|
|
|
|
|
|
|
if (MSG.SystemEvent == 778)
|
|
|
|
|
value = "LOW";
|
|
|
|
|
else if (MSG.SystemEvent == 779)
|
|
|
|
|
value = "MID";
|
|
|
|
|
else if (MSG.SystemEvent == 780)
|
|
|
|
|
value = "HIGH";
|
|
|
|
|
else if (MSG.SystemEvent == 781)
|
|
|
|
|
value = "CRITICAL";
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 782 && MSG.SystemEvent <= 787)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.CAMERA;
|
|
|
|
|
value = (MSG.SystemEvent - 781).ToString();
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, value, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 61440 && MSG.SystemEvent <= 64511)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.SWITCH_PRESS;
|
|
|
|
|
int state = (int)MSG.Data[1] - 240;
|
|
|
|
|
int id = (int)MSG.Data[2];
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, "Unit: " + id + ", State: " + state, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (MSG.SystemEvent >= 64512 && MSG.SystemEvent <= 65535)
|
|
|
|
|
{
|
|
|
|
|
type = enuEventType.UPB_LINK;
|
|
|
|
|
int state = (int)MSG.Data[1] - 252;
|
|
|
|
|
int id = (int)MSG.Data[2];
|
|
|
|
|
|
|
|
|
|
LogEventStatus(type, "Link: " + id + ", State: " + state, alert);
|
|
|
|
|
}
|
|
|
|
|
else if (Global.verbose_unhandled)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < MSG.MessageLength; i++)
|
|
|
|
|
sb.Append(MSG.Data[i].ToString() + " ");
|
|
|
|
|
Event.WriteVerbose("SystemEvent", "Unhandled Raw: " + sb.ToString() + "Num: " + MSG.SystemEvent);
|
|
|
|
|
|
|
|
|
|
int num = ((int)MSG.MessageLength - 1) / 2;
|
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteVerbose("SystemEvent", "Unhandled: " +
|
|
|
|
|
(int)MSG.Data[(i * 2) + 1] + " " + (int)MSG.Data[(i * 2) + 2] + ": " +
|
|
|
|
|
Convert.ToString(MSG.Data[(i * 2) + 1], 2).PadLeft(8, '0') + " " + Convert.ToString(MSG.Data[(i * 2) + 2], 2).PadLeft(8, '0'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleUnsolicitedExtendedStatus(byte[] B)
|
|
|
|
|
{
|
|
|
|
|
clsOL2MsgExtendedStatus MSG = new clsOL2MsgExtendedStatus(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
switch (MSG.ObjectType)
|
|
|
|
|
{
|
|
|
|
|
case enuObjectType.Area:
|
|
|
|
|
for (byte i = 0; i < MSG.AreaCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Areas[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
LogAreaStatus(MSG.ObjectNumber(i));
|
|
|
|
|
|
|
|
|
|
WebNotification.Send("area", Helper.Serialize<AreaContract>(Helper.ConvertArea(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Areas[MSG.ObjectNumber(i)])));
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-11-21 02:31:27 +00:00
|
|
|
|
case enuObjectType.Auxillary:
|
|
|
|
|
for (byte i = 0; i < MSG.AuxStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Zones[MSG.ObjectNumber(i)].CopyAuxExtendedStatus(MSG, i);
|
|
|
|
|
LogZoneStatus(MSG.ObjectNumber(i));
|
|
|
|
|
|
|
|
|
|
if (HAC.Zones[MSG.ObjectNumber(i)].IsTemperatureZone())
|
|
|
|
|
{
|
|
|
|
|
WebNotification.Send("temp", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-11-15 17:37:56 +00:00
|
|
|
|
case enuObjectType.Zone:
|
|
|
|
|
for (byte i = 0; i < MSG.ZoneStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Zones[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
LogZoneStatus(MSG.ObjectNumber(i));
|
|
|
|
|
|
|
|
|
|
switch (HAC.Zones[MSG.ObjectNumber(i)].ZoneType)
|
|
|
|
|
{
|
|
|
|
|
case enuZoneType.EntryExit:
|
|
|
|
|
case enuZoneType.X2EntryDelay:
|
|
|
|
|
case enuZoneType.X4EntryDelay:
|
|
|
|
|
case enuZoneType.Perimeter:
|
|
|
|
|
WebNotification.Send("contact", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
break;
|
|
|
|
|
case enuZoneType.AwayInt:
|
|
|
|
|
WebNotification.Send("motion", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
break;
|
|
|
|
|
case enuZoneType.Water:
|
|
|
|
|
WebNotification.Send("water", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
break;
|
|
|
|
|
case enuZoneType.Fire:
|
|
|
|
|
WebNotification.Send("smoke", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
break;
|
|
|
|
|
case enuZoneType.Gas:
|
|
|
|
|
WebNotification.Send("co", Helper.Serialize<ZoneContract>(Helper.ConvertZone(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Zones[MSG.ObjectNumber(i)])));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Thermostat:
|
|
|
|
|
for (byte i = 0; i < MSG.ThermostatStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
lock (tstat_lock)
|
|
|
|
|
{
|
|
|
|
|
HAC.Thermostats[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
|
|
|
|
|
if (!tstats.ContainsKey(MSG.ObjectNumber(i)))
|
|
|
|
|
tstats.Add(MSG.ObjectNumber(i), DateTime.Now);
|
|
|
|
|
else
|
|
|
|
|
tstats[MSG.ObjectNumber(i)] = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
if (Global.verbose_thermostat_timer)
|
|
|
|
|
Event.WriteVerbose("ThermostatTimer", "Unsolicited status received for " + HAC.Thermostats[MSG.ObjectNumber(i)].Name);
|
|
|
|
|
|
|
|
|
|
WebNotification.Send("thermostat", Helper.Serialize<ThermostatContract>(Helper.ConvertThermostat(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Thermostats[MSG.ObjectNumber(i)])));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Unit:
|
|
|
|
|
for (byte i = 0; i < MSG.UnitStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Units[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
LogUnitStatus(MSG.ObjectNumber(i));
|
|
|
|
|
|
|
|
|
|
WebNotification.Send("unit", Helper.Serialize<UnitContract>(Helper.ConvertUnit(
|
|
|
|
|
MSG.ObjectNumber(i), HAC.Units[MSG.ObjectNumber(i)])));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case enuObjectType.Message:
|
|
|
|
|
for (byte i = 0; i < MSG.MessageCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Messages[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
LogMessageStatus(MSG.ObjectNumber(i));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (Global.verbose_unhandled)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
foreach (byte b in MSG.ToByteArray())
|
|
|
|
|
sb.Append(b.ToString() + " ");
|
|
|
|
|
Event.WriteVerbose("ExtendedStatus", "Unhandled " + MSG.ObjectType.ToString() + " " + sb.ToString());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
private void HandleRequestAuxillaryStatus(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
clsOL2MsgExtendedStatus MSG = new clsOL2MsgExtendedStatus(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
for (byte i = 0; i < MSG.AuxStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
HAC.Zones[MSG.ObjectNumber(i)].CopyAuxExtendedStatus(MSG, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-15 17:37:56 +00:00
|
|
|
|
#region Thermostats
|
|
|
|
|
static double ThermostatTimerInterval()
|
|
|
|
|
{
|
|
|
|
|
DateTime now = DateTime.Now;
|
|
|
|
|
return ((60 - now.Second) * 1000 - now.Millisecond) + new TimeSpan(0, 0, 30).TotalMilliseconds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static DateTime RoundToMinute(DateTime dt)
|
|
|
|
|
{
|
|
|
|
|
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void tstat_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
lock (tstat_lock)
|
|
|
|
|
{
|
|
|
|
|
foreach (KeyValuePair<ushort, DateTime> tstat in tstats)
|
|
|
|
|
{
|
|
|
|
|
// Poll every 4 minutes if no prior update
|
|
|
|
|
if (RoundToMinute(tstat.Value).AddMinutes(4) <= RoundToMinute(DateTime.Now))
|
|
|
|
|
{
|
|
|
|
|
HAC.Connection.Send(new clsOL2MsgRequestExtendedStatus(HAC.Connection, enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus);
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_thermostat_timer)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteVerbose("ThermostatTimer", "Polling status for " + HAC.Thermostats[tstat.Key].Name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log every minute if update within 5 minutes and connected
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (RoundToMinute(tstat.Value).AddMinutes(5) > RoundToMinute(DateTime.Now) &&
|
2016-11-15 17:37:56 +00:00
|
|
|
|
(HAC.Connection.ConnectionState == enuOmniLinkConnectionState.Online ||
|
|
|
|
|
HAC.Connection.ConnectionState == enuOmniLinkConnectionState.OnlineSecure))
|
|
|
|
|
{
|
|
|
|
|
if (HAC.Thermostats[tstat.Key].Temp > 0)
|
|
|
|
|
LogThermostatStatus(tstat.Key);
|
|
|
|
|
else if (Global.verbose_thermostat_timer)
|
|
|
|
|
Event.WriteWarn("ThermostatTimer", "Not logging unknown temp for " + HAC.Thermostats[tstat.Key].Name);
|
|
|
|
|
}
|
|
|
|
|
else if (Global.verbose_thermostat_timer)
|
|
|
|
|
Event.WriteWarn("ThermostatTimer", "Not logging out of date status for " + HAC.Thermostats[tstat.Key].Name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tstat_timer.Interval = ThermostatTimerInterval();
|
|
|
|
|
tstat_timer.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleRequestThermostatStatus(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
clsOL2MsgExtendedStatus MSG = new clsOL2MsgExtendedStatus(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
for (byte i = 0; i < MSG.ThermostatStatusCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
lock (tstat_lock)
|
|
|
|
|
{
|
|
|
|
|
HAC.Thermostats[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
|
|
|
|
|
|
|
|
|
if (!tstats.ContainsKey(MSG.ObjectNumber(i)))
|
|
|
|
|
tstats.Add(MSG.ObjectNumber(i), DateTime.Now);
|
|
|
|
|
else
|
|
|
|
|
tstats[MSG.ObjectNumber(i)] = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
if (Global.verbose_thermostat_timer)
|
|
|
|
|
Event.WriteVerbose("ThermostatTimer", "Polling status received for " + HAC.Thermostats[MSG.ObjectNumber(i)].Name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Time Sync
|
|
|
|
|
static double TimeTimerInterval()
|
|
|
|
|
{
|
|
|
|
|
DateTime now = DateTime.Now;
|
|
|
|
|
return ((60 - now.Second) * 1000 - now.Millisecond);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void tsync_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (tsync_check.AddMinutes(Global.hai_time_interval) < DateTime.Now)
|
2016-11-21 02:31:27 +00:00
|
|
|
|
HAC.Connection.Send(new clsOL2MsgRequestSystemStatus(HAC.Connection), HandleRequestSystemStatus);
|
2016-11-15 17:37:56 +00:00
|
|
|
|
|
|
|
|
|
tsync_timer.Interval = TimeTimerInterval();
|
|
|
|
|
tsync_timer.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleRequestSystemStatus(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
tsync_check = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
clsOL2MsgSystemStatus MSG = new clsOL2MsgSystemStatus(HAC.Connection, B);
|
|
|
|
|
|
|
|
|
|
DateTime time;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// The controller uses 2 digit years and C# uses 4 digit years
|
|
|
|
|
// Extract the 2 digit prefix to use when parsing the time
|
|
|
|
|
int year = DateTime.Now.Year / 100;
|
|
|
|
|
|
|
|
|
|
time = new DateTime((int)MSG.Year + (year * 100), (int)MSG.Month, (int)MSG.Day, (int)MSG.Hour, (int)MSG.Minute, (int)MSG.Second);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
Event.WriteWarn("TimeSyncTimer", "Controller time could not be parsed", true);
|
|
|
|
|
|
|
|
|
|
DateTime now = DateTime.Now;
|
|
|
|
|
HAC.Connection.Send(new clsOL2MsgSetTime(HAC.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
|
|
|
|
(byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime);
|
|
|
|
|
|
|
|
|
|
return;
|
2016-11-21 02:31:27 +00:00
|
|
|
|
}
|
2016-11-15 17:37:56 +00:00
|
|
|
|
|
|
|
|
|
double adj = (DateTime.Now - time).Duration().TotalSeconds;
|
|
|
|
|
|
|
|
|
|
if (adj > Global.hai_time_drift)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteWarn("TimeSyncTimer", "Controller time " + time.ToString("MM/dd/yyyy HH:mm:ss") + " out of sync by " + adj + " seconds", true);
|
|
|
|
|
|
|
|
|
|
DateTime now = DateTime.Now;
|
2016-11-21 02:31:27 +00:00
|
|
|
|
HAC.Connection.Send(new clsOL2MsgSetTime(HAC.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
2016-11-15 17:37:56 +00:00
|
|
|
|
(byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleSetTime(clsOmniLinkMessageQueueItem M, byte[] B, bool Timeout)
|
|
|
|
|
{
|
|
|
|
|
if (Timeout)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Event.WriteVerbose("TimeSyncTimer", "Controller time has been successfully set");
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Logging
|
|
|
|
|
private void LogEventStatus(enuEventType type, string value, bool alert)
|
|
|
|
|
{
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_events (timestamp, name, status)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + type.ToString() + "','" + value + "')");
|
|
|
|
|
|
|
|
|
|
if (alert)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteWarn("SystemEvent", type.ToString() + " " + value);
|
|
|
|
|
Prowl.Notify("SystemEvent", type.ToString() + " " + value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Global.verbose_event)
|
|
|
|
|
Event.WriteVerbose("SystemEvent", type.ToString() + " " + value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogAreaStatus(ushort id)
|
|
|
|
|
{
|
|
|
|
|
clsArea unit = HAC.Areas[id];
|
|
|
|
|
|
|
|
|
|
// Alarm notifcation
|
|
|
|
|
if (unit.AreaFireAlarmText != "OK")
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "FIRE " + unit.Name + " " + unit.AreaFireAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM", "FIRE " + unit.Name + " " + unit.AreaFireAlarmText, ProwlPriority.Emergency);
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (!alarms.Contains("FIRE" + id))
|
2016-11-15 17:37:56 +00:00
|
|
|
|
alarms.Add("FIRE" + id);
|
|
|
|
|
}
|
2016-11-21 02:31:27 +00:00
|
|
|
|
else if (alarms.Contains("FIRE" + id))
|
2016-11-15 17:37:56 +00:00
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "CLEARED - FIRE " + unit.Name + " " + unit.AreaFireAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM CLEARED", "FIRE " + unit.Name + " " + unit.AreaFireAlarmText, ProwlPriority.High);
|
|
|
|
|
|
|
|
|
|
alarms.Remove("FIRE" + id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unit.AreaBurglaryAlarmText != "OK")
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "BURGLARY " + unit.Name + " " + unit.AreaBurglaryAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM", "BURGLARY " + unit.Name + " " + unit.AreaBurglaryAlarmText, ProwlPriority.Emergency);
|
|
|
|
|
|
|
|
|
|
if (!alarms.Contains("BURGLARY" + id))
|
|
|
|
|
alarms.Add("BURGLARY" + id);
|
|
|
|
|
}
|
|
|
|
|
else if (alarms.Contains("BURGLARY" + id))
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "CLEARED - BURGLARY " + unit.Name + " " + unit.AreaBurglaryAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM CLEARED", "BURGLARY " + unit.Name + " " + unit.AreaBurglaryAlarmText, ProwlPriority.High);
|
|
|
|
|
|
|
|
|
|
alarms.Remove("BURGLARY" + id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unit.AreaAuxAlarmText != "OK")
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "AUX " + unit.Name + " " + unit.AreaAuxAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM", "AUX " + unit.Name + " " + unit.AreaAuxAlarmText, ProwlPriority.Emergency);
|
|
|
|
|
|
|
|
|
|
if (!alarms.Contains("AUX" + id))
|
|
|
|
|
alarms.Add("AUX" + id);
|
|
|
|
|
}
|
|
|
|
|
else if (alarms.Contains("AUX" + id))
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "CLEARED - AUX " + unit.Name + " " + unit.AreaAuxAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM CLEARED", "AUX " + unit.Name + " " + unit.AreaAuxAlarmText, ProwlPriority.High);
|
|
|
|
|
|
|
|
|
|
alarms.Remove("AUX" + id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unit.AreaDuressAlarmText != "OK")
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "DURESS " + unit.Name + " " + unit.AreaDuressAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM", "DURESS " + unit.Name + " " + unit.AreaDuressAlarmText, ProwlPriority.Emergency);
|
|
|
|
|
|
|
|
|
|
if (!alarms.Contains("DURESS" + id))
|
|
|
|
|
alarms.Add("DURESS" + id);
|
|
|
|
|
}
|
|
|
|
|
else if (alarms.Contains("DURESS" + id))
|
|
|
|
|
{
|
|
|
|
|
Event.WriteAlarm("AreaStatus", "CLEARED - DURESS " + unit.Name + " " + unit.AreaDuressAlarmText);
|
|
|
|
|
Prowl.Notify("ALARM CLEARED", "DURESS " + unit.Name + " " + unit.AreaDuressAlarmText, ProwlPriority.High);
|
|
|
|
|
|
|
|
|
|
alarms.Remove("DURESS" + id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string status = unit.ModeText();
|
|
|
|
|
|
|
|
|
|
if (unit.ExitTimer > 0)
|
|
|
|
|
status = "ARMING " + status;
|
|
|
|
|
|
|
|
|
|
if (unit.EntryTimer > 0)
|
|
|
|
|
status = "TRIPPED " + status;
|
|
|
|
|
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_areas (timestamp, id, name,
|
|
|
|
|
fire, police, auxiliary,
|
|
|
|
|
duress, security)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + id.ToString() + "','" + unit.Name + "','" +
|
|
|
|
|
unit.AreaFireAlarmText + "','" + unit.AreaBurglaryAlarmText + "','" + unit.AreaAuxAlarmText + "','" +
|
|
|
|
|
unit.AreaDuressAlarmText + "','" + status + "')");
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_area)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteVerbose("AreaStatus", id + " " + unit.Name + ", Status: " + status);
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (unit.LastMode != unit.AreaMode)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Prowl.Notify("Security", unit.Name + " " + unit.ModeText());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogZoneStatus(ushort id)
|
|
|
|
|
{
|
|
|
|
|
clsZone unit = HAC.Zones[id];
|
|
|
|
|
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_zones (timestamp, id, name, status)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + id.ToString() + "','" + unit.Name + "','" + unit.StatusText() + "')");
|
2016-11-21 02:31:27 +00:00
|
|
|
|
|
|
|
|
|
if (Global.verbose_zone)
|
|
|
|
|
{
|
|
|
|
|
if (unit.IsTemperatureZone())
|
|
|
|
|
Event.WriteVerbose("ZoneStatus", id + " " + unit.Name + ", Temp: " + unit.TempText());
|
|
|
|
|
else
|
|
|
|
|
Event.WriteVerbose("ZoneStatus", id + " " + unit.Name + ", Status: " + unit.StatusText());
|
|
|
|
|
}
|
2016-11-15 17:37:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogThermostatStatus(ushort id)
|
|
|
|
|
{
|
|
|
|
|
clsThermostat unit = HAC.Thermostats[id];
|
|
|
|
|
|
|
|
|
|
int temp, heat, cool, humidity, humidify, dehumidify;
|
|
|
|
|
|
|
|
|
|
Int32.TryParse(unit.TempText(), out temp);
|
|
|
|
|
Int32.TryParse(unit.HeatSetpointText(), out heat);
|
|
|
|
|
Int32.TryParse(unit.CoolSetpointText(), out cool);
|
|
|
|
|
Int32.TryParse(unit.HumidityText(), out humidity);
|
|
|
|
|
Int32.TryParse(unit.HumidifySetpointText(), out humidify);
|
|
|
|
|
Int32.TryParse(unit.DehumidifySetpointText(), out dehumidify);
|
|
|
|
|
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_thermostats (timestamp, id, name,
|
|
|
|
|
status, temp, heat, cool,
|
|
|
|
|
humidity, humidify, dehumidify,
|
|
|
|
|
mode, fan, hold)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + "','" + id.ToString() + "','" + unit.Name + "','" +
|
|
|
|
|
unit.HorC_StatusText() + "','" + temp.ToString() + "','" + heat + "','" + cool + "','" +
|
|
|
|
|
humidity + "','" + humidify + "','" + dehumidify + "','" +
|
|
|
|
|
unit.ModeText() + "','" + unit.FanModeText() + "','" + unit.HoldStatusText() + "')");
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_thermostat)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteVerbose("ThermostatStatus", id + " " + unit.Name +
|
2016-11-21 02:31:27 +00:00
|
|
|
|
", Status: " + unit.TempText() + " " + unit.HorC_StatusText() +
|
2016-11-15 17:37:56 +00:00
|
|
|
|
", Heat: " + unit.HeatSetpointText() +
|
2016-11-21 02:31:27 +00:00
|
|
|
|
", Cool: " + unit.CoolSetpointText() +
|
|
|
|
|
", Mode: " + unit.ModeText() +
|
|
|
|
|
", Fan: " + unit.FanModeText() +
|
2016-11-15 17:37:56 +00:00
|
|
|
|
", Hold: " + unit.HoldStatusText());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogUnitStatus(ushort id)
|
|
|
|
|
{
|
|
|
|
|
clsUnit unit = HAC.Units[id];
|
|
|
|
|
|
|
|
|
|
string status = unit.StatusText;
|
|
|
|
|
|
|
|
|
|
if (unit.Status == 100 && unit.StatusTime == 0)
|
|
|
|
|
status = "OFF";
|
|
|
|
|
else if (unit.Status == 200 && unit.StatusTime == 0)
|
|
|
|
|
status = "ON";
|
|
|
|
|
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_units (timestamp, id, name,
|
|
|
|
|
status, statusvalue, statustime)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + id.ToString() + "','" + unit.Name + "','" +
|
|
|
|
|
status + "','" + unit.Status + "','" + unit.StatusTime + "')");
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_unit)
|
|
|
|
|
Event.WriteVerbose("UnitStatus", id + " " + unit.Name + ", Status: " + status);
|
2016-11-15 17:37:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogMessageStatus(ushort id)
|
|
|
|
|
{
|
|
|
|
|
clsMessage unit = HAC.Messages[id];
|
|
|
|
|
|
|
|
|
|
DBQueue(@"
|
|
|
|
|
INSERT INTO log_messages (timestamp, id, name, status)
|
|
|
|
|
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + id.ToString() + "','" + unit.Name + "','" + unit.StatusText() + "')");
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.verbose_message)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Event.WriteVerbose("MessageStatus", unit.Name + ", " + unit.StatusText());
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (Global.prowl_messages)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
Prowl.Notify("Message", id + " " + unit.Name + ", " + unit.StatusText());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Database
|
|
|
|
|
public bool DBOpen()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (mysql_conn.State != ConnectionState.Open)
|
|
|
|
|
mysql_conn.Open();
|
|
|
|
|
|
|
|
|
|
mysql_retry = DateTime.MinValue;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Event.WriteError("DatabaseLogger", "Failed to connect to database\r\n" + ex.Message);
|
|
|
|
|
mysql_retry = DateTime.Now.AddMinutes(1);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DBClose()
|
|
|
|
|
{
|
2016-11-21 02:31:27 +00:00
|
|
|
|
if (mysql_conn.State != ConnectionState.Closed)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
mysql_conn.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DBQueue(string query)
|
|
|
|
|
{
|
|
|
|
|
if (!Global.mysql_logging)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-21 02:31:27 +00:00
|
|
|
|
lock (mysql_lock)
|
2016-11-15 17:37:56 +00:00
|
|
|
|
mysql_queue.Enqueue(query);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int DBQueueCount()
|
|
|
|
|
{
|
|
|
|
|
int count;
|
|
|
|
|
lock (mysql_lock)
|
|
|
|
|
count = mysql_queue.Count;
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
2016-11-21 02:31:27 +00:00
|
|
|
|
}
|