mirror of
https://github.com/excaliburpartners/OmniLinkBridge
synced 2024-12-22 10:42:24 +00:00
1.0.5 - Added web service API for Samsung SmartThings integration
This commit is contained in:
parent
e24c25d80d
commit
828308717a
22
HAILogger.sln
Normal file
22
HAILogger.sln
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HAILogger", "HAILogger\HAILogger.csproj", "{0A636707-98BA-45AB-9843-AED430933CEE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0A636707-98BA-45AB-9843-AED430933CEE}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{0A636707-98BA-45AB-9843-AED430933CEE}.Debug|x86.Build.0 = Debug|x86
|
||||
{0A636707-98BA-45AB-9843-AED430933CEE}.Release|x86.ActiveCfg = Release|x86
|
||||
{0A636707-98BA-45AB-9843-AED430933CEE}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
16
HAILogger/App.config
Normal file
16
HAILogger/App.config
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.diagnostics>
|
||||
<switches>
|
||||
<!-- This switch controls data messages. In order to receive data
|
||||
trace messages, change value="0" to value="1" -->
|
||||
<add name="DataMessagesSwitch" value="0"/>
|
||||
<!-- This switch controls general messages. In order to
|
||||
receive general trace messages change the value to the
|
||||
appropriate level. "1" gives error messages, "2" gives errors
|
||||
and warnings, "3" gives more detailed error information, and
|
||||
"4" gives verbose trace information -->
|
||||
<add name="TraceLevelSwitch" value="3"/>
|
||||
</switches>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
|
29
HAILogger/AreaContract.cs
Normal file
29
HAILogger/AreaContract.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class AreaContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string name { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string burglary { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string co { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string fire { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string water { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string mode { get; set; }
|
||||
}
|
||||
}
|
14
HAILogger/CommandContract.cs
Normal file
14
HAILogger/CommandContract.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class CommandContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort value { get; set; }
|
||||
}
|
||||
}
|
1214
HAILogger/CoreServer.cs
Normal file
1214
HAILogger/CoreServer.cs
Normal file
File diff suppressed because it is too large
Load diff
165
HAILogger/Event.cs
Normal file
165
HAILogger/Event.cs
Normal file
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
static class Event
|
||||
{
|
||||
public static void WriteVerbose(string value)
|
||||
{
|
||||
Trace.WriteLine(value);
|
||||
LogFile(TraceLevel.Verbose, "VERBOSE", value);
|
||||
}
|
||||
|
||||
public static void WriteVerbose(string source, string value)
|
||||
{
|
||||
Trace.WriteLine("VERBOSE: " + source + ": " + value);
|
||||
LogFile(TraceLevel.Verbose, "VERBOSE: " + source, value);
|
||||
}
|
||||
|
||||
public static void WriteInfo(string source, string value, bool alert)
|
||||
{
|
||||
WriteInfo(source, value);
|
||||
if (alert)
|
||||
{
|
||||
LogEvent(EventLogEntryType.Information, source, value);
|
||||
SendMail("Info", source, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteInfo(string source, string value)
|
||||
{
|
||||
Trace.WriteLine("INFO: " + source + ": " + value);
|
||||
LogFile(TraceLevel.Info, "INFO: " + source, value);
|
||||
}
|
||||
|
||||
public static void WriteWarn(string source, string value, bool alert)
|
||||
{
|
||||
WriteWarn(source, value);
|
||||
if (alert)
|
||||
SendMail("Warn", source, value);
|
||||
}
|
||||
|
||||
public static void WriteWarn(string source, string value)
|
||||
{
|
||||
Trace.WriteLine("WARN: " + source + ": " + value);
|
||||
LogFile(TraceLevel.Warning, "WARN: " + source, value);
|
||||
LogEvent(EventLogEntryType.Warning, source, value);
|
||||
}
|
||||
|
||||
public static void WriteError(string source, string value)
|
||||
{
|
||||
Trace.WriteLine("ERROR: " + source + ": " + value);
|
||||
LogFile(TraceLevel.Error, "ERROR: " + source, value);
|
||||
LogEvent(EventLogEntryType.Error, source, value);
|
||||
SendMail("Error", source, value);
|
||||
}
|
||||
|
||||
public static void WriteAlarm(string source, string value)
|
||||
{
|
||||
Trace.WriteLine("ALARM: " + source + ": " + value);
|
||||
LogFile(TraceLevel.Error, "ALARM: " + source, value);
|
||||
LogEvent(EventLogEntryType.Warning, source, value);
|
||||
|
||||
if (Global.mail_alarm_to != null && Global.mail_alarm_to.Length > 0)
|
||||
{
|
||||
MailMessage mail = new MailMessage();
|
||||
mail.From = Global.mail_from;
|
||||
foreach (MailAddress address in Global.mail_alarm_to)
|
||||
mail.To.Add(address);
|
||||
mail.Priority = MailPriority.High;
|
||||
mail.Subject = value;
|
||||
mail.Body = value;
|
||||
|
||||
SmtpClient smtp = new SmtpClient(Global.mail_server, Global.mail_port);
|
||||
|
||||
if (!string.IsNullOrEmpty(Global.mail_username))
|
||||
{
|
||||
smtp.UseDefaultCredentials = false;
|
||||
smtp.Credentials = new NetworkCredential(Global.mail_username, Global.mail_password);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
smtp.Send(mail);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string error = "An error occurred sending email notification\r\n" + ex.Message;
|
||||
LogFile(TraceLevel.Error, "ERROR: " + source, error);
|
||||
LogEvent(EventLogEntryType.Error, "EventNotification", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SendMail(string level, string source, string value)
|
||||
{
|
||||
if (Global.mail_to == null || Global.mail_to.Length == 0)
|
||||
return;
|
||||
|
||||
MailMessage mail = new MailMessage();
|
||||
mail.From = Global.mail_from;
|
||||
foreach (MailAddress address in Global.mail_to)
|
||||
mail.To.Add(address);
|
||||
mail.Subject = Global.event_source + " - " + level;
|
||||
mail.Body = source + ": " + value;
|
||||
|
||||
SmtpClient smtp = new SmtpClient(Global.mail_server, Global.mail_port);
|
||||
|
||||
if (!string.IsNullOrEmpty(Global.mail_username))
|
||||
{
|
||||
smtp.UseDefaultCredentials = false;
|
||||
smtp.Credentials = new NetworkCredential(Global.mail_username, Global.mail_password);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
smtp.Send(mail);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string error = "An error occurred sending email notification\r\n" + ex.Message;
|
||||
LogFile(TraceLevel.Error, "ERROR: " + source, error);
|
||||
LogEvent(EventLogEntryType.Error, "EventNotification", error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogEvent(EventLogEntryType type, string source, string value)
|
||||
{
|
||||
string event_log = "Application";
|
||||
|
||||
if (!EventLog.SourceExists(Global.event_source))
|
||||
EventLog.CreateEventSource(Global.event_source, event_log);
|
||||
|
||||
string event_msg = source + ": " + value;
|
||||
|
||||
EventLog.WriteEntry(Global.event_source, event_msg, type, 234);
|
||||
}
|
||||
|
||||
private static void LogFile(TraceLevel level, string source, string value)
|
||||
{
|
||||
TraceSwitch tswitch = new TraceSwitch("TraceLevelSwitch", "Trace Level for Entire Application");
|
||||
|
||||
if (tswitch.Level < level)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
FileStream fs = new FileStream(Global.dir_config + "\\" + Global.event_log, FileMode.Append, FileAccess.Write);
|
||||
StreamWriter sw = new StreamWriter(fs);
|
||||
|
||||
sw.WriteLine(DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss ") + source + ": " + value);
|
||||
|
||||
sw.Close();
|
||||
fs.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogEvent(EventLogEntryType.Error, "EventLogger", "Unable to write to the file log.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
HAILogger/Global.cs
Normal file
54
HAILogger/Global.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System.Net.Mail;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
public abstract class Global
|
||||
{
|
||||
// Events Preset
|
||||
public static string event_log;
|
||||
public static string event_source;
|
||||
|
||||
// Directories
|
||||
public static string dir_config;
|
||||
|
||||
// HAI Controller
|
||||
public static string hai_address;
|
||||
public static int hai_port;
|
||||
public static string hai_key1;
|
||||
public static string hai_key2;
|
||||
public static bool hai_time_sync;
|
||||
public static int hai_time_interval;
|
||||
public static int hai_time_drift;
|
||||
|
||||
// mySQL Database
|
||||
public static bool mysql_logging;
|
||||
public static string mysql_connection;
|
||||
|
||||
// Events
|
||||
public static string mail_server;
|
||||
public static int mail_port;
|
||||
public static string mail_username;
|
||||
public static string mail_password;
|
||||
public static MailAddress mail_from;
|
||||
public static MailAddress[] mail_to;
|
||||
public static MailAddress[] mail_alarm_to;
|
||||
|
||||
// Prowl Notifications
|
||||
public static string[] prowl_key;
|
||||
public static bool prowl_messages;
|
||||
|
||||
// Web Service
|
||||
public static bool webapi_enabled;
|
||||
public static int webapi_port;
|
||||
|
||||
// Verbose Output
|
||||
public static bool verbose_unhandled;
|
||||
public static bool verbose_event;
|
||||
public static bool verbose_area;
|
||||
public static bool verbose_zone;
|
||||
public static bool verbose_thermostat_timer;
|
||||
public static bool verbose_thermostat;
|
||||
public static bool verbose_unit;
|
||||
public static bool verbose_message;
|
||||
}
|
||||
}
|
BIN
HAILogger/HAI.Controller.dll
Normal file
BIN
HAILogger/HAI.Controller.dll
Normal file
Binary file not shown.
107
HAILogger/HAILogger.csproj
Normal file
107
HAILogger/HAILogger.csproj
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0A636707-98BA-45AB-9843-AED430933CEE}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>HAILogger</RootNamespace>
|
||||
<AssemblyName>HAILogger</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="HAI.Controller">
|
||||
<HintPath>.\HAI.Controller.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.ServiceModel.Web" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CoreServer.cs" />
|
||||
<Compile Include="Event.cs" />
|
||||
<Compile Include="Global.cs" />
|
||||
<Compile Include="HAIService.cs" />
|
||||
<Compile Include="Helper.cs" />
|
||||
<Compile Include="CommandContract.cs" />
|
||||
<Compile Include="IHAIService.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="ProjectInstaller.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ProjectInstaller.Designer.cs">
|
||||
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Prowl.cs" />
|
||||
<Compile Include="Service.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Service.Designer.cs">
|
||||
<DependentUpon>Service.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="SubscribeContract.cs" />
|
||||
<Compile Include="ThermostatContract.cs" />
|
||||
<Compile Include="NameContract.cs" />
|
||||
<Compile Include="AreaContract.cs" />
|
||||
<Compile Include="ZoneContract.cs" />
|
||||
<Compile Include="UnitContract.cs" />
|
||||
<Compile Include="WebNotification.cs" />
|
||||
<Compile Include="WebService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="HAILogger.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ProjectInstaller.resx">
|
||||
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Service.resx">
|
||||
<DependentUpon>Service.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
55
HAILogger/HAILogger.ini
Normal file
55
HAILogger/HAILogger.ini
Normal file
|
@ -0,0 +1,55 @@
|
|||
# HAI Controller
|
||||
hai_address =
|
||||
hai_port = 4369
|
||||
hai_key1 = 00-00-00-00-00-00-00-00
|
||||
hai_key2 = 00-00-00-00-00-00-00-00
|
||||
|
||||
# HAI Controller Time Sync (yes/no)
|
||||
# hai_time_check is interval in minutes to check controller time
|
||||
# hai_time_adj is the drift in seconds to allow before an adjustment is made
|
||||
hai_time_sync = yes
|
||||
hai_time_interval = 60
|
||||
hai_time_drift = 10
|
||||
|
||||
# mySQL Database Logging (yes/no)
|
||||
mysql_logging = no
|
||||
mysql_server =
|
||||
mysql_database =
|
||||
mysql_user =
|
||||
mysql_password =
|
||||
|
||||
# Event Notifications
|
||||
# mail_username and mail_password optional for authenticated mail
|
||||
# mail_to sent for service notifications
|
||||
# mail_alarm_to sent for FIRE, BURGLARY, AUX, DURESS
|
||||
mail_server =
|
||||
mail_port = 25
|
||||
mail_username =
|
||||
mail_password =
|
||||
mail_from =
|
||||
#mail_to =
|
||||
#mail_to =
|
||||
#mail_alarm_to =
|
||||
#mail_alarm_to =
|
||||
|
||||
# Prowl Notifications
|
||||
# Register for API key at http://www.prowlapp.com
|
||||
# Sent for FIRE, BURGLARY, AUX, DURESS
|
||||
# prowl_messages (yes/no) for console message notifications
|
||||
#prowl_key =
|
||||
#prowl_key =
|
||||
prowl_messages = no
|
||||
|
||||
# Web service
|
||||
# Used for integration with Samsung SmartThings
|
||||
webapi_enabled = yes
|
||||
webapi_port = 8000
|
||||
|
||||
# Verbose Output (yes/no)
|
||||
verbose_unhandled = yes
|
||||
verbose_area = yes
|
||||
verbose_zone = yes
|
||||
verbose_thermostat_timer = yes
|
||||
verbose_thermostat = yes
|
||||
verbose_unit = yes
|
||||
verbose_message = yes
|
275
HAILogger/HAIService.cs
Normal file
275
HAILogger/HAIService.cs
Normal file
|
@ -0,0 +1,275 @@
|
|||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Web;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
|
||||
public class HAIService : IHAIService
|
||||
{
|
||||
public void Subscribe(SubscribeContract contract)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "Subscribe");
|
||||
WebNotification.AddSubscription(contract.callback);
|
||||
}
|
||||
|
||||
public List<NameContract> ListAreas()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListAreas");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Areas.Count; i++)
|
||||
{
|
||||
clsArea area = WebService.HAC.Areas[i];
|
||||
|
||||
if (area.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = area.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public AreaContract GetArea(ushort id)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "GetArea: " + id);
|
||||
|
||||
WebOperationContext ctx = WebOperationContext.Current;
|
||||
ctx.OutgoingResponse.Headers.Add("type", "area");
|
||||
|
||||
clsArea area = WebService.HAC.Areas[id];
|
||||
return Helper.ConvertArea(id, area);
|
||||
}
|
||||
|
||||
public List<NameContract> ListZonesContact()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListZonesContact");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = WebService.HAC.Zones[i];
|
||||
|
||||
if ((zone.ZoneType == enuZoneType.EntryExit ||
|
||||
zone.ZoneType == enuZoneType.X2EntryDelay ||
|
||||
zone.ZoneType == enuZoneType.X4EntryDelay ||
|
||||
zone.ZoneType == enuZoneType.Perimeter) && zone.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = zone.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public List<NameContract> ListZonesMotion()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListZonesMotion");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = WebService.HAC.Zones[i];
|
||||
|
||||
if (zone.ZoneType == enuZoneType.AwayInt && zone.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = zone.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public List<NameContract> ListZonesWater()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListZonesWater");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = WebService.HAC.Zones[i];
|
||||
|
||||
if (zone.ZoneType == enuZoneType.Water && zone.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = zone.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public List<NameContract> ListZonesSmoke()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListZonesSmoke");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = WebService.HAC.Zones[i];
|
||||
|
||||
if (zone.ZoneType == enuZoneType.Fire && zone.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = zone.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public List<NameContract> ListZonesCO()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListZonesCO");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = WebService.HAC.Zones[i];
|
||||
|
||||
if (zone.ZoneType == enuZoneType.Gas && zone.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = zone.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public ZoneContract GetZone(ushort id)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "GetZone: " + id);
|
||||
|
||||
WebOperationContext ctx = WebOperationContext.Current;
|
||||
|
||||
switch (WebService.HAC.Zones[id].ZoneType)
|
||||
{
|
||||
case enuZoneType.EntryExit:
|
||||
case enuZoneType.X2EntryDelay:
|
||||
case enuZoneType.X4EntryDelay:
|
||||
case enuZoneType.Perimeter:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "contact");
|
||||
break;
|
||||
case enuZoneType.AwayInt:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "motion");
|
||||
break;
|
||||
case enuZoneType.Water:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "water");
|
||||
break;
|
||||
case enuZoneType.Fire:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "smoke");
|
||||
break;
|
||||
case enuZoneType.Gas:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "co");
|
||||
break;
|
||||
default:
|
||||
ctx.OutgoingResponse.Headers.Add("type", "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
clsZone unit = WebService.HAC.Zones[id];
|
||||
return Helper.ConvertZone(id, unit);
|
||||
}
|
||||
|
||||
public List<NameContract> ListUnits()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListUnits");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Units.Count; i++)
|
||||
{
|
||||
clsUnit unit = WebService.HAC.Units[i];
|
||||
|
||||
if (unit.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = unit.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public UnitContract GetUnit(ushort id)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "GetUnit: " + id);
|
||||
|
||||
WebOperationContext ctx = WebOperationContext.Current;
|
||||
ctx.OutgoingResponse.Headers.Add("type", "unit");
|
||||
|
||||
clsUnit unit = WebService.HAC.Units[id];
|
||||
return Helper.ConvertUnit(id, unit);
|
||||
}
|
||||
|
||||
public void SetUnit(CommandContract unit)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "SetUnit: " + unit.id + " to " + unit.value + "%");
|
||||
|
||||
if (unit.value == 0)
|
||||
WebService.HAC.SendCommand(enuUnitCommand.Off, 0, unit.id);
|
||||
else if (unit.value == 100)
|
||||
WebService.HAC.SendCommand(enuUnitCommand.On, 0, unit.id);
|
||||
else
|
||||
WebService.HAC.SendCommand(enuUnitCommand.Level, BitConverter.GetBytes(unit.value)[0], unit.id);
|
||||
}
|
||||
|
||||
|
||||
public void SetUnitKeypadPress(CommandContract unit)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "SetUnitKeypadPress: " + unit.id + " to " + unit.value + " button");
|
||||
WebService.HAC.SendCommand(enuUnitCommand.LutronHomeWorksKeypadButtonPress, BitConverter.GetBytes(unit.value)[0], unit.id);
|
||||
}
|
||||
|
||||
public List<NameContract> ListThermostats()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListThermostats");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Thermostats.Count; i++)
|
||||
{
|
||||
clsThermostat unit = WebService.HAC.Thermostats[i];
|
||||
|
||||
if (unit.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = unit.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public ThermostatContract GetThermostat(ushort id)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "GetThermostat: " + id);
|
||||
|
||||
WebOperationContext ctx = WebOperationContext.Current;
|
||||
ctx.OutgoingResponse.Headers.Add("type", "thermostat");
|
||||
|
||||
clsThermostat unit = WebService.HAC.Thermostats[id];
|
||||
return Helper.ConvertThermostat(id, unit);
|
||||
}
|
||||
|
||||
public void SetThermostatCoolSetpoint(CommandContract unit)
|
||||
{
|
||||
int temp = Helper.ConvertTemperature(unit.value);
|
||||
Event.WriteVerbose("WebService", "SetThermostatCoolSetpoint: " + unit.id + " to " + unit.value + "F (" + temp + ")");
|
||||
WebService.HAC.SendCommand(enuUnitCommand.SetHighSetPt, BitConverter.GetBytes(temp)[0], unit.id);
|
||||
}
|
||||
|
||||
public void SetThermostatHeatSetpoint(CommandContract unit)
|
||||
{
|
||||
int temp = Helper.ConvertTemperature(unit.value);
|
||||
Event.WriteVerbose("WebService", "SetThermostatCoolSetpoint: " + unit.id + " to " + unit.value + "F (" + temp + ")");
|
||||
WebService.HAC.SendCommand(enuUnitCommand.SetLowSetPt, BitConverter.GetBytes(temp)[0], unit.id);
|
||||
}
|
||||
|
||||
public void SetThermostatMode(CommandContract unit)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "SetThermostatMode: " + unit.id + " to " + unit.value);
|
||||
WebService.HAC.SendCommand(enuUnitCommand.Mode, BitConverter.GetBytes(unit.value)[0], unit.id);
|
||||
}
|
||||
|
||||
public void SetThermostatFanMode(CommandContract unit)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "SetThermostatFanMode: " + unit.id + " to " + unit.value);
|
||||
WebService.HAC.SendCommand(enuUnitCommand.Fan, BitConverter.GetBytes(unit.value)[0], unit.id);
|
||||
}
|
||||
|
||||
public List<NameContract> ListButtons()
|
||||
{
|
||||
Event.WriteVerbose("WebService", "ListButtons");
|
||||
|
||||
List<NameContract> names = new List<NameContract>();
|
||||
for (ushort i = 1; i < WebService.HAC.Buttons.Count; i++)
|
||||
{
|
||||
clsButton unit = WebService.HAC.Buttons[i];
|
||||
|
||||
if (unit.DefaultProperties == false)
|
||||
names.Add(new NameContract() { id = i, name = unit.Name });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public void PushButton(CommandContract unit)
|
||||
{
|
||||
Event.WriteVerbose("WebService", "PushButton: " + unit.id);
|
||||
WebService.HAC.SendCommand(enuUnitCommand.Button, 0, unit.id);
|
||||
}
|
||||
}
|
||||
}
|
107
HAILogger/Helper.cs
Normal file
107
HAILogger/Helper.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using HAI_Shared;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
static class Helper
|
||||
{
|
||||
public static AreaContract ConvertArea(ushort id, clsArea area)
|
||||
{
|
||||
AreaContract ret = new AreaContract();
|
||||
|
||||
ret.id = id;
|
||||
ret.name = area.Name;
|
||||
ret.burglary = area.AreaBurglaryAlarmText;
|
||||
ret.co = area.AreaGasAlarmText;
|
||||
ret.fire = area.AreaFireAlarmText;
|
||||
ret.water = area.AreaWaterAlarmText;
|
||||
|
||||
string mode = area.ModeText();
|
||||
|
||||
if (mode.Contains("OFF"))
|
||||
ret.mode = "OFF";
|
||||
else if (mode.Contains("DAY"))
|
||||
ret.mode = "DAY";
|
||||
else if (mode.Contains("NIGHT"))
|
||||
ret.mode = "NIGHT";
|
||||
else if (mode.Contains("AWAY"))
|
||||
ret.mode = "AWAY";
|
||||
else if (mode.Contains("VACATION"))
|
||||
ret.mode = "VACATION";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static ZoneContract ConvertZone(ushort id, clsZone zone)
|
||||
{
|
||||
ZoneContract ret = new ZoneContract();
|
||||
|
||||
ret.id = id;
|
||||
ret.name = zone.Name;
|
||||
ret.status = zone.StatusText();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static UnitContract ConvertUnit(ushort id, clsUnit unit)
|
||||
{
|
||||
UnitContract ret = new UnitContract();
|
||||
|
||||
ret.id = id;
|
||||
ret.name = unit.Name;
|
||||
|
||||
if (unit.Status > 100)
|
||||
ret.level = (ushort)(unit.Status - 100);
|
||||
else if (unit.Status == 1)
|
||||
ret.level = 100;
|
||||
else
|
||||
ret.level = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static ThermostatContract ConvertThermostat(ushort id, clsThermostat unit)
|
||||
{
|
||||
ThermostatContract ret = new ThermostatContract();
|
||||
|
||||
ret.id = id;
|
||||
ret.name = unit.Name;
|
||||
|
||||
ushort temp, heat, cool, humidity;
|
||||
|
||||
ushort.TryParse(unit.TempText(), out temp);
|
||||
ushort.TryParse(unit.HeatSetpointText(), out heat);
|
||||
ushort.TryParse(unit.CoolSetpointText(), out cool);
|
||||
ushort.TryParse(unit.HumidityText(), out humidity);
|
||||
|
||||
ret.temp = temp;
|
||||
ret.humidity = humidity;
|
||||
ret.heatsetpoint = heat;
|
||||
ret.coolsetpoint = cool;
|
||||
ret.mode = unit.Mode;
|
||||
ret.fanmode = unit.FanMode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int ConvertTemperature(int f)
|
||||
{
|
||||
// Convert to celsius
|
||||
double c = 5.0 / 9.0 * (f - 32);
|
||||
|
||||
// Convert to omni temp (0 is -40C and 255 is 87.5C)
|
||||
return (int)Math.Round((c + 40) * 2, 0);
|
||||
}
|
||||
|
||||
public static string Serialize<T>(T obj)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
|
||||
ser.WriteObject(stream, obj);
|
||||
return Encoding.UTF8.GetString(stream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
94
HAILogger/IHAIService.cs
Normal file
94
HAILogger/IHAIService.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Web;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[ServiceContract]
|
||||
public interface IHAIService
|
||||
{
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void Subscribe(SubscribeContract contract);
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListAreas();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
AreaContract GetArea(ushort id);
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListZonesContact();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListZonesMotion();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListZonesWater();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListZonesSmoke();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListZonesCO();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
ZoneContract GetZone(ushort id);
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListUnits();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
UnitContract GetUnit(ushort id);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetUnit(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetUnitKeypadPress(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListThermostats();
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
ThermostatContract GetThermostat(ushort id);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetThermostatCoolSetpoint(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetThermostatHeatSetpoint(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetThermostatMode(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void SetThermostatFanMode(CommandContract unit);
|
||||
|
||||
[OperationContract]
|
||||
[WebGet(ResponseFormat = WebMessageFormat.Json)]
|
||||
List<NameContract> ListButtons();
|
||||
|
||||
[OperationContract]
|
||||
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
|
||||
void PushButton(CommandContract unit);
|
||||
}
|
||||
}
|
14
HAILogger/NameContract.cs
Normal file
14
HAILogger/NameContract.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class NameContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
54
HAILogger/Program.cs
Normal file
54
HAILogger/Program.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceProcess;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static CoreServer server;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
switch (args[i])
|
||||
{
|
||||
case "-c":
|
||||
Global.dir_config = args[++i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Environment.UserInteractive)
|
||||
{
|
||||
Console.TreatControlCAsInput = false;
|
||||
Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
|
||||
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
|
||||
|
||||
server = new CoreServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ServiceBase[] ServicesToRun;
|
||||
|
||||
// More than one user Service may run within the same process. To add
|
||||
// another service to this process, change the following line to
|
||||
// create a second service object. For example,
|
||||
//
|
||||
// ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
|
||||
//
|
||||
ServicesToRun = new ServiceBase[] { new Service() };
|
||||
|
||||
ServiceBase.Run(ServicesToRun);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void myHandler(object sender, ConsoleCancelEventArgs args)
|
||||
{
|
||||
server.Shutdown();
|
||||
args.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
56
HAILogger/ProjectInstaller.Designer.cs
generated
Normal file
56
HAILogger/ProjectInstaller.Designer.cs
generated
Normal file
|
@ -0,0 +1,56 @@
|
|||
namespace HAILogger
|
||||
{
|
||||
partial class ProjectInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.serviceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
|
||||
this.serviceInstaller = new System.ServiceProcess.ServiceInstaller();
|
||||
//
|
||||
// serviceProcessInstaller
|
||||
//
|
||||
this.serviceProcessInstaller.Password = null;
|
||||
this.serviceProcessInstaller.Username = null;
|
||||
//
|
||||
// serviceInstaller
|
||||
//
|
||||
this.serviceInstaller.ServiceName = "HAILogger";
|
||||
//
|
||||
// ProjectInstaller
|
||||
//
|
||||
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
|
||||
this.serviceProcessInstaller,
|
||||
this.serviceInstaller});
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller;
|
||||
private System.ServiceProcess.ServiceInstaller serviceInstaller;
|
||||
}
|
||||
}
|
17
HAILogger/ProjectInstaller.cs
Normal file
17
HAILogger/ProjectInstaller.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration.Install;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[RunInstaller(true)]
|
||||
public partial class ProjectInstaller : System.Configuration.Install.Installer
|
||||
{
|
||||
public ProjectInstaller()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
129
HAILogger/ProjectInstaller.resx
Normal file
129
HAILogger/ProjectInstaller.resx
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="serviceProcessInstaller.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="serviceInstaller.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>196, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
36
HAILogger/Properties/AssemblyInfo.cs
Normal file
36
HAILogger/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("HAILogger")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Excalibur Partners, LLC")]
|
||||
[assembly: AssemblyProduct("HAILogger")]
|
||||
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("469a23b2-7f66-4a98-a3a0-fb539ae08bf8")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.5.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.5.0")]
|
50
HAILogger/Prowl.cs
Normal file
50
HAILogger/Prowl.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
public enum ProwlPriority
|
||||
{
|
||||
VeryLow = -2,
|
||||
Moderate = -1,
|
||||
Normal = 0,
|
||||
High = 1,
|
||||
Emergency = 2,
|
||||
};
|
||||
|
||||
static class Prowl
|
||||
{
|
||||
public static void Notify(string source, string description)
|
||||
{
|
||||
Notify(source, description, ProwlPriority.Normal);
|
||||
}
|
||||
|
||||
public static void Notify(string source, string description, ProwlPriority priority)
|
||||
{
|
||||
Uri URI = new Uri("https://api.prowlapp.com/publicapi/add");
|
||||
|
||||
foreach (string key in Global.prowl_key)
|
||||
{
|
||||
List<string> parameters = new List<string>();
|
||||
|
||||
parameters.Add("apikey=" + key);
|
||||
parameters.Add("priority= " + (int)priority);
|
||||
parameters.Add("application=" + Global.event_source);
|
||||
parameters.Add("event=" + source);
|
||||
parameters.Add("description=" + description);
|
||||
|
||||
WebClient client = new WebClient();
|
||||
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
|
||||
client.UploadStringAsync(URI, string.Join("&", parameters.ToArray()));
|
||||
client.UploadStringCompleted += client_UploadStringCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
static void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
|
||||
{
|
||||
if(e.Error != null)
|
||||
Event.WriteError("ProwlNotification", "An error occurred sending notification\r\n" + e.Error.Message);
|
||||
}
|
||||
}
|
||||
}
|
42
HAILogger/Service.Designer.cs
generated
Normal file
42
HAILogger/Service.Designer.cs
generated
Normal file
|
@ -0,0 +1,42 @@
|
|||
namespace HAILogger
|
||||
{
|
||||
partial class Service
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
//
|
||||
// Service
|
||||
//
|
||||
this.AutoLog = false;
|
||||
this.CanShutdown = true;
|
||||
this.ServiceName = "HAILogger";
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
35
HAILogger/Service.cs
Normal file
35
HAILogger/Service.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
partial class Service : ServiceBase
|
||||
{
|
||||
static CoreServer server;
|
||||
|
||||
public Service()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnStart(string[] args)
|
||||
{
|
||||
server = new CoreServer();
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
server.Shutdown();
|
||||
}
|
||||
|
||||
protected override void OnShutdown()
|
||||
{
|
||||
server.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
123
HAILogger/Service.resx
Normal file
123
HAILogger/Service.resx
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
259
HAILogger/Settings.cs
Normal file
259
HAILogger/Settings.cs
Normal file
|
@ -0,0 +1,259 @@
|
|||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
static class Settings
|
||||
{
|
||||
public static void LoadSettings()
|
||||
{
|
||||
NameValueCollection settings = LoadCollection(Global.dir_config + "\\HAILogger.ini");
|
||||
|
||||
// HAI Controller
|
||||
Global.hai_address = settings["hai_address"];
|
||||
Global.hai_port = ValidatePort(settings, "hai_port");
|
||||
Global.hai_key1 = settings["hai_key1"];
|
||||
Global.hai_key2 = settings["hai_key2"];
|
||||
Global.hai_time_sync = ValidateYesNo(settings, "hai_time_sync");
|
||||
Global.hai_time_interval = ValidateInt(settings, "hai_time_interval");
|
||||
Global.hai_time_drift = ValidateInt(settings, "hai_time_drift");
|
||||
|
||||
// mySQL Database
|
||||
Global.mysql_logging = ValidateYesNo(settings, "mysql_logging");
|
||||
Global.mysql_connection = settings["mysql_connection"];
|
||||
|
||||
// Events
|
||||
Global.mail_server = settings["mail_server"];
|
||||
Global.mail_port = ValidatePort(settings, "mail_port");
|
||||
Global.mail_username = settings["mail_username"];
|
||||
Global.mail_password = settings["mail_password"];
|
||||
Global.mail_from = ValidateMailFrom(settings, "mail_from");
|
||||
Global.mail_to = ValidateMailTo(settings, "mail_to");
|
||||
Global.mail_alarm_to = ValidateMailTo(settings, "mail_alarm_to");
|
||||
|
||||
// Prowl Notifications
|
||||
Global.prowl_key = ValidateMultipleStrings(settings, "prowl_key");
|
||||
Global.prowl_messages = ValidateYesNo(settings, "prowl_messages");
|
||||
|
||||
// Web Service
|
||||
Global.webapi_enabled = ValidateYesNo(settings, "webapi_enabled");
|
||||
Global.webapi_port = ValidatePort(settings, "webapi_port");
|
||||
|
||||
// Verbose Output
|
||||
Global.verbose_unhandled = ValidateYesNo(settings, "verbose_unhandled");
|
||||
Global.verbose_event = ValidateYesNo(settings, "verbose_event");
|
||||
Global.verbose_area = ValidateYesNo(settings, "verbose_area");
|
||||
Global.verbose_zone = ValidateYesNo(settings, "verbose_zone");
|
||||
Global.verbose_thermostat_timer = ValidateYesNo(settings, "verbose_thermostat_timer");
|
||||
Global.verbose_thermostat = ValidateYesNo(settings, "verbose_thermostat");
|
||||
Global.verbose_unit = ValidateYesNo(settings, "verbose_unit");
|
||||
Global.verbose_message = ValidateYesNo(settings, "verbose_message");
|
||||
}
|
||||
|
||||
private static int ValidateInt(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Int32.Parse(settings[section]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid integer specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateInt shouldn't reach here");
|
||||
}
|
||||
|
||||
private static int ValidatePort(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
int port = Int32.Parse(settings[section]);
|
||||
|
||||
if (port < 1 || port > 65534)
|
||||
throw new Exception();
|
||||
|
||||
return port;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid port specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidatePort shouldn't reach here");
|
||||
}
|
||||
|
||||
private static bool ValidateBool(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Boolean.Parse(settings[section]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid bool specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateBool shouldn't reach here");
|
||||
}
|
||||
|
||||
private static IPAddress ValidateIP(NameValueCollection settings, string section)
|
||||
{
|
||||
if (settings[section] == "*")
|
||||
return IPAddress.Any;
|
||||
|
||||
if (settings[section] == "")
|
||||
return IPAddress.None;
|
||||
|
||||
try
|
||||
{
|
||||
return IPAddress.Parse(section);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid IP specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateIP shouldn't reach here");
|
||||
}
|
||||
|
||||
private static string ValidateDirectory(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(settings[section]))
|
||||
Directory.CreateDirectory(settings[section]);
|
||||
|
||||
return settings[section];
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid directory specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateDirectory shouldn't reach here");
|
||||
}
|
||||
|
||||
private static MailAddress ValidateMailFrom(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MailAddress(settings[section]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid email specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateMailFrom shouldn't reach here");
|
||||
}
|
||||
|
||||
private static MailAddress[] ValidateMailTo(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(settings[section] == null)
|
||||
return new MailAddress[] {};
|
||||
|
||||
string[] emails = settings[section].Split(',');
|
||||
MailAddress[] addresses = new MailAddress[emails.Length];
|
||||
|
||||
for(int i=0; i < emails.Length; i++)
|
||||
addresses[i] = new MailAddress(emails[i]);
|
||||
|
||||
return addresses;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid email specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateMailTo shouldn't reach here");
|
||||
}
|
||||
|
||||
private static string[] ValidateMultipleStrings(NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (settings[section] == null)
|
||||
return new string[] { };
|
||||
|
||||
return settings[section].Split(',');
|
||||
}
|
||||
catch
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid string specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateMultipleStrings shouldn't reach here");
|
||||
}
|
||||
|
||||
private static bool ValidateYesNo (NameValueCollection settings, string section)
|
||||
{
|
||||
if (settings[section] == null)
|
||||
return false;
|
||||
if (string.Compare(settings[section], "yes", true) == 0)
|
||||
return true;
|
||||
else if (string.Compare(settings[section], "no", true) == 0)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
Event.WriteError("Settings", "Invalid yes/no specified for " + section);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
throw new Exception("ValidateYesNo shouldn't reach here");
|
||||
}
|
||||
|
||||
private static NameValueCollection LoadCollection(string sFile)
|
||||
{
|
||||
NameValueCollection settings = new NameValueCollection();
|
||||
|
||||
try
|
||||
{
|
||||
FileStream fs = new FileStream(sFile, FileMode.Open, FileAccess.Read);
|
||||
StreamReader sr = new StreamReader(fs);
|
||||
|
||||
while (true)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
string[] split = line.Split('=');
|
||||
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
split[i] = split[i].Trim();
|
||||
|
||||
if (split.Length == 2)
|
||||
settings.Add(split[0], split[1]);
|
||||
}
|
||||
|
||||
sr.Close();
|
||||
fs.Close();
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
Event.WriteError("Settings", "Unable to parse settings file " + sFile);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
11
HAILogger/SubscribeContract.cs
Normal file
11
HAILogger/SubscribeContract.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class SubscribeContract
|
||||
{
|
||||
[DataMember]
|
||||
public string callback { get; set; }
|
||||
}
|
||||
}
|
33
HAILogger/ThermostatContract.cs
Normal file
33
HAILogger/ThermostatContract.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using HAI_Shared;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class ThermostatContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string name { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort temp { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort humidity { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort coolsetpoint { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort heatsetpoint { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public enuThermostatMode mode { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public enuThermostatFanMode fanmode { get; set; }
|
||||
}
|
||||
}
|
17
HAILogger/UnitContract.cs
Normal file
17
HAILogger/UnitContract.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class UnitContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string name { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public ushort level { get; set; }
|
||||
}
|
||||
}
|
50
HAILogger/WebNotification.cs
Normal file
50
HAILogger/WebNotification.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
static class WebNotification
|
||||
{
|
||||
private static List<string> subscriptions = new List<string>();
|
||||
|
||||
public static void AddSubscription(string callback)
|
||||
{
|
||||
if (!subscriptions.Contains(callback))
|
||||
{
|
||||
Event.WriteVerbose("WebRequest", "Adding subscription to " + callback);
|
||||
subscriptions.Add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Send(string type, string body)
|
||||
{
|
||||
WebClient client = new WebClient();
|
||||
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
|
||||
client.Headers.Add("type", type);
|
||||
client.UploadStringCompleted += client_UploadStringCompleted;
|
||||
|
||||
foreach (string subscription in subscriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.UploadStringAsync(new Uri(subscription), "POST", body, subscription);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Event.WriteError("WebNotification", "An error occurred sending notification to " + subscription + "\r\n" + ex.ToString());
|
||||
subscriptions.Remove(subscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
Event.WriteError("WebNotification", "An error occurred sending notification to " + e.UserState.ToString() + "\r\n" + e.Error.Message);
|
||||
subscriptions.Remove(e.UserState.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
HAILogger/WebService.cs
Normal file
44
HAILogger/WebService.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using HAI_Shared;
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Web;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
public class WebService
|
||||
{
|
||||
public static clsHAC HAC;
|
||||
WebServiceHost host;
|
||||
|
||||
public WebService(clsHAC hac)
|
||||
{
|
||||
HAC = hac;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Uri uri = new Uri("http://0.0.0.0:" + Global.webapi_port + "/");
|
||||
host = new WebServiceHost(typeof(HAIService), uri);
|
||||
|
||||
try
|
||||
{
|
||||
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IHAIService), new WebHttpBinding(), "");
|
||||
host.Open();
|
||||
|
||||
Event.WriteInfo("WebService", "Listening on " + uri.ToString());
|
||||
}
|
||||
catch (CommunicationException ex)
|
||||
{
|
||||
Event.WriteError("WebService", "An exception occurred: " + ex.Message);
|
||||
host.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (host != null)
|
||||
host.Close();
|
||||
}
|
||||
}
|
||||
}
|
17
HAILogger/ZoneContract.cs
Normal file
17
HAILogger/ZoneContract.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace HAILogger
|
||||
{
|
||||
[DataContract]
|
||||
public class ZoneContract
|
||||
{
|
||||
[DataMember]
|
||||
public ushort id { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string name { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string status { get; set; }
|
||||
}
|
||||
}
|
85
README.md
85
README.md
|
@ -1,2 +1,87 @@
|
|||
# HAILogger
|
||||
Provides logging and web service API for HAI/Leviton OmniPro II controllers
|
||||
|
||||
##Download
|
||||
You can download the [binary here](http://www.excalibur-partners.com/downloads/HAILogger_1_0_5.zip)
|
||||
|
||||
##Requirements
|
||||
- .NET Framework 4.0
|
||||
- mySQL 5.1 ODBC Connector
|
||||
|
||||
##Operation
|
||||
- Area, Messages, Units, and Zones are logged to mySQL when status changes
|
||||
- Thermostats are logged to mySQL once per minute
|
||||
- If no notifications are received within 4 minutes a request is issued
|
||||
- After 5 minutes of no updates a warning will be logged and mySQL will not be updated
|
||||
- If the temp is 0 a warning will be logged and mySQL will not be updated
|
||||
- Controller time is checked and compared to the local computer time disregarding time zones
|
||||
|
||||
##Notifications
|
||||
- Emails are sent to mail_alarm_to when an area status changes
|
||||
- Prowl notifications are sent when an areas status changes
|
||||
|
||||
##Installation
|
||||
1. Copy files to your desiered location like C:\HAILogger
|
||||
2. Create mySQL database and import HAILogger.sql
|
||||
3. Update HAILogger.ini with settings
|
||||
4. Run HAILogger.exe and verify everything is working
|
||||
5. For Windows Service run install.bat / uninstall.bat
|
||||
|
||||
##MySQL Setup
|
||||
You will want to install the MySQL Community Server, Workbench, and ODBC Connector. The Workbench software provides a graphical interface to administer the MySQL server. The HAI Logger uses ODBC to communicate with the database. The MySQL ODBC Connector library is needed for Windows ODBC to communicate with MySQL. Make sure you install version 5.1 of the MySQL ODBC Connector provided in the link below.
|
||||
|
||||
http://dev.mysql.com/downloads/mysql/
|
||||
http://dev.mysql.com/downloads/tools/workbench/
|
||||
http://dev.mysql.com/downloads/connector/odbc/5.1.html
|
||||
|
||||
After installing MySQL server it should have asked you to setup an instance. One of the steps of the instance wizard was to create a root password. Assuming you installed the HAI Logger on the same computer you will want to use the below settings in HAILogger.ini.
|
||||
|
||||
mysql_server = localhost
|
||||
mysql_user = root
|
||||
mysql_password = password you set in the wizard
|
||||
|
||||
At this point we need to open MySQL Workbench to create the database (called a schema in the Workbench GUI) for HAILogger to use.
|
||||
|
||||
1. After opening the program double-click on "Local instance MySQL" and enter the password you set in the wizard.
|
||||
2. On the toolbar click the "Create a new schema" button, provide a name, and click apply.
|
||||
3. On the left side right-click on the schema you created and click "Set as default schema".
|
||||
4. In the middle section under Query1 click the open file icon and select the HAILogger.sql file.
|
||||
5. Click the Execute lighting bolt to run the query, which will create the tables.
|
||||
|
||||
Lastly in HAILogger.ini set mysql_database to the name of the schema you created. This should get you up and running. The MySQL Workbench can also be used to view the data that HAILogger inserts into the tables.
|
||||
|
||||
##Web Service API
|
||||
To test the API you can use your browser to view a page or PowerShell (see below) to change a value.
|
||||
|
||||
- http://localhost:8000/ListUnits
|
||||
- http://localhost:8000/GetUnit?id=1
|
||||
- Invoke-WebRequest -Uri "http://localhost:8000/SetUnit" -Method POST -ContentType "application/json" -Body (convertto-json -InputObject @{"id"=1;"value"=100}) -UseBasicParsing
|
||||
|
||||
##Change Log
|
||||
Version 1.0.5 - 2016-11-15
|
||||
- Added web service API for Samsung SmartThings integration
|
||||
|
||||
Version 1.0.4 - 2014-05-08
|
||||
- Merged HAILogger.exe and HAILoggerService.exe
|
||||
- Added immediate time sync after controller reconnect
|
||||
|
||||
Version 1.0.3 - 2013-01-06
|
||||
- Added setting for prowl console message notification
|
||||
- Added settings for verbose output control
|
||||
- Added setting to enable mySQL logging
|
||||
- Added queue to mySQL logging
|
||||
- Changed mySQL log time from mySQL NOW() to computer time
|
||||
- Changed prowl notifications to be asynchronous
|
||||
- Fixed crash when prowl api down
|
||||
- Fixed setting yes/no parsing so no setting works
|
||||
- Fixed incorrect thermostat out of date status warning
|
||||
|
||||
Version 1.0.2 - 2012-12-30
|
||||
- Fixed thermostat invalid mySQL logging error
|
||||
|
||||
Version 1.0.1 - 2012-12-30
|
||||
- Added setting to adjust time sync interval
|
||||
- Fixed crash when controller time not initially set
|
||||
|
||||
Version 1.0.0 - 2012-12-29
|
||||
- Initial release
|
Loading…
Reference in a new issue