Added NightAlert project for travel kit
This commit is contained in:
16
NightScout/Alerters/Alerter.cs
Normal file
16
NightScout/Alerters/Alerter.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public abstract class Alerter : IAlerter
|
||||
{
|
||||
public abstract void StartAlert();
|
||||
public abstract void StartStaleDataAlert();
|
||||
public abstract void StartUrgentAlert();
|
||||
public abstract void StopAlerts();
|
||||
}
|
||||
}
|
||||
32
NightScout/Alerters/ConsoleAlerter.cs
Normal file
32
NightScout/Alerters/ConsoleAlerter.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class ConsoleAlerter : IAlerter
|
||||
{
|
||||
|
||||
public void StartAlert()
|
||||
{
|
||||
Console.WriteLine("Alerting");
|
||||
}
|
||||
|
||||
public void StartUrgentAlert()
|
||||
{
|
||||
Console.WriteLine("Urgent Alerting");
|
||||
}
|
||||
|
||||
public void StartStaleDataAlert()
|
||||
{
|
||||
Console.WriteLine("Stale Data Alerting");
|
||||
}
|
||||
|
||||
public void StopAlerts()
|
||||
{
|
||||
Console.WriteLine("Alerts stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
81
NightScout/Alerters/MultiAlerter.cs
Normal file
81
NightScout/Alerters/MultiAlerter.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class MultiAlerter : IAlerter
|
||||
{
|
||||
public List<IAlerter> Alerters { get; set; }
|
||||
|
||||
public MultiAlerter(IEnumerable<IAlerter> alerters)
|
||||
{
|
||||
Alerters = new List<IAlerter>(alerters);
|
||||
}
|
||||
public void StartAlert()
|
||||
{
|
||||
Alerters.ForEach(a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
a.StartAlert();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void StartUrgentAlert()
|
||||
{
|
||||
Alerters.ForEach(a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
a.StartUrgentAlert();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void StartStaleDataAlert()
|
||||
{
|
||||
Alerters.ForEach(a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
a.StartStaleDataAlert();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void StopAlerts()
|
||||
{
|
||||
|
||||
Alerters.ForEach(a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
a.StopAlerts();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
81
NightScout/Alerters/RaspberryPiAudioAlert.cs
Normal file
81
NightScout/Alerters/RaspberryPiAudioAlert.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NightScout.Interfaces;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class RaspberryPiAudioAlert : IAlerter
|
||||
{
|
||||
public String PlayerCommandLine { get; set; }
|
||||
public String KillCommand { get; set; }
|
||||
public String AlertFileName { get; set; }
|
||||
|
||||
protected IRaspberryPiButtonSource ButtonSource;
|
||||
|
||||
private Boolean playing = false;
|
||||
|
||||
|
||||
public RaspberryPiAudioAlert()
|
||||
{
|
||||
this.PlayerCommandLine = "\"mpg123 -q {0}\"";
|
||||
this.KillCommand = "pkill mpg123";
|
||||
this.AlertFileName = "~/ratm.mp3";
|
||||
}
|
||||
|
||||
public RaspberryPiAudioAlert(String playerCommandline)
|
||||
: base()
|
||||
{
|
||||
this.PlayerCommandLine = playerCommandline;
|
||||
}
|
||||
|
||||
public RaspberryPiAudioAlert(String playerCommandline, IRaspberryPiButtonSource buttonSource)
|
||||
: this(playerCommandline)
|
||||
{
|
||||
this.ButtonSource = buttonSource;
|
||||
this.ButtonSource.ButtonStateChange += ButtonSource_ButtonStateChange;
|
||||
}
|
||||
|
||||
public RaspberryPiAudioAlert(IRaspberryPiButtonSource buttonSource)
|
||||
: this()
|
||||
{
|
||||
this.ButtonSource = buttonSource;
|
||||
this.ButtonSource.ButtonStateChange += ButtonSource_ButtonStateChange;
|
||||
}
|
||||
|
||||
private void ButtonSource_ButtonStateChange(bool obj)
|
||||
{
|
||||
Console.WriteLine("Button state change: {0}", obj);
|
||||
if(obj)
|
||||
StopAlerts();
|
||||
}
|
||||
|
||||
public void StartAlert()
|
||||
{
|
||||
if (!playing)
|
||||
{
|
||||
playing = true;
|
||||
Process.Start("/bin/bash", String.Format("-c {0}", String.Format(PlayerCommandLine,AlertFileName )));
|
||||
}
|
||||
}
|
||||
|
||||
public void StartUrgentAlert()
|
||||
{
|
||||
StartAlert();
|
||||
}
|
||||
|
||||
public void StartStaleDataAlert()
|
||||
{
|
||||
StartAlert();
|
||||
}
|
||||
|
||||
public void StopAlerts()
|
||||
{
|
||||
Process.Start("/bin/bash", "-c \"pkill mpg123\"");
|
||||
playing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
NightScout/App.config
Normal file
67
NightScout/App.config
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||
</startup>
|
||||
|
||||
<appSettings>
|
||||
<add key="ButtonSourceEnabled" value="false"/>
|
||||
<add key="NightscoutEndpoint" value="" />
|
||||
<add key="NightscoutCredentials" value="" />
|
||||
</appSettings>
|
||||
|
||||
<log4net>
|
||||
<appender name="RootRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
|
||||
<param name="File" value="NightScout.log" />
|
||||
<param name="AppendToFile" value="true" />
|
||||
<param name="MaxSizeRollBackups" value="62" />
|
||||
<param name="RollingStyle" value="Date" />
|
||||
<datePattern value="yyyy-MM-dd" />
|
||||
<param name="StaticLogFileName" value="true" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<param name="Header" value="*****************************************************
* NightScout Alerter
* 
* started...
" />
|
||||
<param name="Footer" value="...End of server logging.
" />
|
||||
<param name="ConversionPattern" value="%d [%t] %-5p %-30.37c{2} - %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="RootRollingLogFileAppender" />
|
||||
</root>
|
||||
</log4net>
|
||||
|
||||
<runtime>
|
||||
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
|
||||
<dependentAssembly>
|
||||
|
||||
<assemblyIdentity name="WebSocket4Net" publicKeyToken="eb4e154b696bf72a" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.15.2.11" newVersion="0.15.2.11" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
<dependentAssembly>
|
||||
|
||||
<assemblyIdentity name="SuperSocket.ClientEngine" publicKeyToken="ee9af13f57f00acc" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.10.0.0" newVersion="0.10.0.0" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
<dependentAssembly>
|
||||
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
</assemblyBinding>
|
||||
|
||||
</runtime>
|
||||
</configuration>
|
||||
10
NightScout/Interfaces/IAlerter.cs
Normal file
10
NightScout/Interfaces/IAlerter.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace NightScout
|
||||
{
|
||||
public interface IAlerter
|
||||
{
|
||||
void StartAlert();
|
||||
void StartUrgentAlert();
|
||||
void StartStaleDataAlert();
|
||||
void StopAlerts();
|
||||
}
|
||||
}
|
||||
19
NightScout/Interfaces/INightscoutDataSource.cs
Normal file
19
NightScout/Interfaces/INightscoutDataSource.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public interface INightscoutDataSource
|
||||
{
|
||||
event Action Connected;
|
||||
event Action<Object> DataUpdate;
|
||||
event Action<Object> SocketError;
|
||||
event Action<Object> Alarm;
|
||||
event Action<Object> UrgentAlarm;
|
||||
event Action<Object> ClearAlarm;
|
||||
event Action StaleDataAlarm;
|
||||
void Emit(String eventName, String data);
|
||||
void Emit(String eventName, JObject data);
|
||||
void Authorize();
|
||||
}
|
||||
}
|
||||
12
NightScout/Interfaces/IRaspberryPiButtonSource.cs
Normal file
12
NightScout/Interfaces/IRaspberryPiButtonSource.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NightScout.Interfaces
|
||||
{
|
||||
public interface IRaspberryPiButtonSource
|
||||
{
|
||||
event Action<Boolean> ButtonStateChange;
|
||||
}
|
||||
}
|
||||
112
NightScout/NightScoutAlert.csproj
Normal file
112
NightScout/NightScoutAlert.csproj
Normal file
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{D74FA0D0-8487-47F3-AB25-A65D221A2F47}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NightScout</RootNamespace>
|
||||
<AssemblyName>NightScout</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net40-full\log4net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.11.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Raspberry.IO, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\Raspberry.IO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Raspberry.IO.GeneralPurpose, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\Raspberry.IO.GeneralPurpose.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Raspberry.IO.Interop, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\Raspberry.IO.Interop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Raspberry.System, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\Raspberry.System.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Alerters\Alerter.cs" />
|
||||
<Compile Include="Alerters\ConsoleAlerter.cs" />
|
||||
<Compile Include="Interfaces\IAlerter.cs" />
|
||||
<Compile Include="Interfaces\INightscoutDataSource.cs" />
|
||||
<Compile Include="Interfaces\IRaspberryPiButtonSource.cs" />
|
||||
<Compile Include="Alerters\MultiAlerter.cs" />
|
||||
<Compile Include="NightscoutAlerter.cs" />
|
||||
<Compile Include="Alerters\RaspberryPiAudioAlert.cs" />
|
||||
<Compile Include="RaspberryPIButtonSource.cs" />
|
||||
<Compile Include="SocketIONightscoutDataSource.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NightscoutLibrary\NightscoutLibrary.csproj">
|
||||
<Project>{59dc2b0b-2d94-4841-a181-d3e1124ba5f2}</Project>
|
||||
<Name>NightscoutLibrary</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ThirdParty\EngineIoClientDotNet\Src\EngineIoClientDotNet.net40\EngineIoClientDotNet.net40.csproj">
|
||||
<Project>{833dbca1-0b01-4477-9937-a8e50e426ee5}</Project>
|
||||
<Name>EngineIoClientDotNet.net40</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ThirdParty\SocketIoClientDotNet\Src\SocketIoClientDotNet.net40\SocketIoClientDotNet.net40.csproj">
|
||||
<Project>{53ae4914-a35b-406c-91ed-7e3d9c950f45}</Project>
|
||||
<Name>SocketIoClientDotNet.net40</Name>
|
||||
</ProjectReference>
|
||||
</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>
|
||||
39
NightScout/NightscoutAlerter.cs
Normal file
39
NightScout/NightscoutAlerter.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class NightscoutAlerter
|
||||
{
|
||||
public INightscoutDataSource DataSource { get; set; }
|
||||
public IAlerter Alerter { get; set; }
|
||||
public DateTime LastDataUpdateReceived { get; set; }
|
||||
|
||||
public NightscoutAlerter(INightscoutDataSource dataSource, IAlerter alerter)
|
||||
{
|
||||
DataSource = dataSource;
|
||||
Alerter = alerter;
|
||||
SetupEvents();
|
||||
}
|
||||
|
||||
private void SetupEvents()
|
||||
{
|
||||
DataSource.Connected += () => DataSource.Authorize();
|
||||
DataSource.Alarm += (alarm) => Alerter.StartAlert();
|
||||
DataSource.UrgentAlarm += (alarm) => Alerter.StartUrgentAlert();
|
||||
DataSource.ClearAlarm += (alarm) => Alerter.StopAlerts();
|
||||
DataSource.StaleDataAlarm += () => Alerter.StartStaleDataAlert();
|
||||
|
||||
//DataSource.DataUpdate += DataSource_DataUpdate;
|
||||
}
|
||||
|
||||
void DataSource_DataUpdate(object obj)
|
||||
{
|
||||
Console.WriteLine(obj);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
136
NightScout/Program.cs
Normal file
136
NightScout/Program.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using NightScout;
|
||||
using NightscoutLibrary.Configuration;
|
||||
using Quobject.SocketIoClientDotNet.Client;
|
||||
|
||||
namespace NightScoutAlert
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
if (args.Any(arg => arg.Equals("--test-audio")))
|
||||
{
|
||||
Console.WriteLine("Starting audio test...");
|
||||
RaspberryPiAudioAlert alerter = new RaspberryPiAudioAlert();
|
||||
alerter.StartAlert();
|
||||
Thread.Sleep(3000);
|
||||
alerter.StopAlerts();
|
||||
return;
|
||||
}
|
||||
Quobject.EngineIoClientDotNet.Modules.LogManager.Enabled = true;
|
||||
|
||||
//NightscoutTestConfiguration configuration = new NightscoutTestConfiguration();
|
||||
//MonoCompatibleNightscoutAlertConfiguration configuration = new MonoCompatibleNightscoutAlertConfiguration("http://nightscout.chrispr.org:8082", "ThisIsATerribleAuthSystem");
|
||||
String nightscoutEndpoint = ConfigurationManager.AppSettings["NightscoutEndpoint"];
|
||||
String nightscoutCredentials = ConfigurationManager.AppSettings["NightscoutCredentials"];
|
||||
if (String.IsNullOrEmpty(nightscoutEndpoint) || String.IsNullOrEmpty(nightscoutCredentials))
|
||||
{
|
||||
Console.WriteLine("The nightscout endpoint and credentials must be filled into the App.config");
|
||||
return;
|
||||
}
|
||||
MonoCompatibleNightscoutAlertConfiguration configuration = new MonoCompatibleNightscoutAlertConfiguration(nightscoutEndpoint, nightscoutCredentials);
|
||||
RaspberryPIButtonSource buttonSource = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["ButtonSourceEnabled"]) &&
|
||||
Boolean.Parse(ConfigurationManager.AppSettings["ButtonSourceEnabled"]))
|
||||
{
|
||||
buttonSource = new RaspberryPIButtonSource(1);
|
||||
Console.WriteLine("Button source made");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{}
|
||||
|
||||
NightscoutDataSource dataSource =null;
|
||||
RaspberryPiAudioAlert audioAlerter = null;
|
||||
|
||||
if (buttonSource != null)
|
||||
{
|
||||
dataSource = new NightscoutDataSource(configuration,
|
||||
log4net.LogManager.GetLogger("NightscoutAlert"), buttonSource);
|
||||
audioAlerter = new RaspberryPiAudioAlert(buttonSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataSource = new NightscoutDataSource(configuration,
|
||||
log4net.LogManager.GetLogger("NightscoutAlert"));
|
||||
audioAlerter = new RaspberryPiAudioAlert();
|
||||
}
|
||||
ILog log = log4net.LogManager.GetLogger("NightscoutAlertMain");
|
||||
log.Debug("Log started");
|
||||
ConsoleAlerter consoleAlerter = new ConsoleAlerter();
|
||||
//
|
||||
|
||||
NightscoutAlerter nightscoutAlerter = new NightscoutAlerter(dataSource,
|
||||
new MultiAlerter(new IAlerter[] {consoleAlerter, audioAlerter, buttonSource}));
|
||||
|
||||
//var socket = IO.Socket(configuration.NightscoutBaseURL);
|
||||
|
||||
//socket.On(Socket.EVENT_CONNECT, () =>
|
||||
//{
|
||||
// Console.WriteLine("Connected...");
|
||||
// JObject authRequest = new JObject();
|
||||
// authRequest.Add("client", "web");
|
||||
|
||||
// socket.Emit("authorize", authRequest);
|
||||
//});
|
||||
//socket.On(Socket.EVENT_ERROR, (obj) =>
|
||||
//{
|
||||
// Console.WriteLine(obj.ToString());
|
||||
//});
|
||||
|
||||
//socket.On("dataUpdate", (data) =>
|
||||
//{
|
||||
// Console.WriteLine(data);
|
||||
//});
|
||||
|
||||
//socket.On("alarm", (data) =>
|
||||
//{
|
||||
// Console.WriteLine(data.ToString());
|
||||
//});
|
||||
|
||||
//socket.On(Socket.EVENT_MESSAGE, (data) =>
|
||||
//{
|
||||
// Console.WriteLine(data.ToString());
|
||||
//});
|
||||
|
||||
//socket.On("urgent_alarm", (data) =>
|
||||
//{
|
||||
// Console.WriteLine(data.ToString());
|
||||
//});
|
||||
|
||||
//socket.On("clear_alarm", (data) =>
|
||||
//{
|
||||
// Console.WriteLine(data.ToString());
|
||||
//});
|
||||
Console.WriteLine("Started");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
class NightscoutTestConfiguration : INightscoutAlertConfiguration
|
||||
{
|
||||
|
||||
public String NightscoutBaseURL
|
||||
{
|
||||
//get { return "http://straylight.chrispr.lan:8082"; }
|
||||
get { return "http://192.168.1.100:8082"; }
|
||||
set
|
||||
{throw new NotImplementedException();}
|
||||
}
|
||||
|
||||
public string APISecretKey
|
||||
{
|
||||
get { return "ThisIsATerribleAuthSystem"; }
|
||||
set
|
||||
{throw new NotImplementedException();}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
NightScout/Properties/AssemblyInfo.cs
Normal file
38
NightScout/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
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("NightScout")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NightScout")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[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("5d91c91b-21c0-428c-9937-74115daa2861")]
|
||||
|
||||
// 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.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
|
||||
105
NightScout/RaspberryPIButtonSource.cs
Normal file
105
NightScout/RaspberryPIButtonSource.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NightScout.Interfaces;
|
||||
using Raspberry.IO.GeneralPurpose;
|
||||
using Raspberry.IO.GeneralPurpose.Behaviors;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class RaspberryPIButtonSource : IRaspberryPiButtonSource, IAlerter
|
||||
{
|
||||
public event Action<bool> ButtonStateChange;
|
||||
|
||||
protected IGpioConnectionDriver PinDriver;
|
||||
protected GpioOutputBinaryPin ButtonLEDPin;
|
||||
|
||||
private static readonly object ledLock = new object();
|
||||
|
||||
public RaspberryPIButtonSource(Int32 pinNumber)
|
||||
: this(pinNumber, new FileGpioConnectionDriver())
|
||||
{ }
|
||||
|
||||
public RaspberryPIButtonSource(Int32 pinNumber, IGpioConnectionDriver driver)
|
||||
{
|
||||
//Attempt to monitor the pin
|
||||
//pinConfiguration = ConnectorPin.P1Pin11.Input().Name("Switch");
|
||||
//pinConfiguration.Reversed = true;
|
||||
//pinConfiguration.OnStatusChanged(PinChangeHandler);
|
||||
|
||||
|
||||
//if(pinConfiguration == null)
|
||||
// Console.WriteLine("null");
|
||||
//PinDriver = new FileGpioConnectionDriver();
|
||||
PinDriver = driver;
|
||||
//var settings = new GpioConnectionSettings { Driver = pinConnectionDriver };
|
||||
|
||||
Console.WriteLine("Making new GPIO connection");
|
||||
//pinConnection = new GpioConnection(settings,pinConfiguration);
|
||||
//pinConnectionDriver.Allocate(ProcessorPin.Pin17, PinDirection.Input);
|
||||
//var pinDriver = pinConnectionDriver.In(ConnectorPin.P1Pin11);
|
||||
var buttonPin = PinDriver.In(ConnectorPin.P1Pin16);
|
||||
ButtonLEDPin = PinDriver.Out(ConnectorPin.P1Pin22);
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
Boolean savedState = false;
|
||||
while (true)
|
||||
{
|
||||
//Pin 11 is inverse (always high unless button is pressed)
|
||||
Boolean state = !(buttonPin.Read());
|
||||
if (savedState != state)
|
||||
{
|
||||
PinChangeHandler(state);
|
||||
savedState = state;
|
||||
}
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
});
|
||||
//Console.WriteLine("Made");
|
||||
//pinConnection.PinStatusChanged += pinConnection_PinStatusChanged;
|
||||
}
|
||||
|
||||
private void PinChangeHandler(Boolean state)
|
||||
{
|
||||
if (ButtonStateChange != null)
|
||||
ButtonStateChange(state);
|
||||
}
|
||||
|
||||
|
||||
public void StartAlert()
|
||||
{
|
||||
lock (ledLock)
|
||||
{
|
||||
ButtonLEDPin.Write(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartUrgentAlert()
|
||||
{
|
||||
lock (ledLock)
|
||||
{
|
||||
ButtonLEDPin.Write(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartStaleDataAlert()
|
||||
{
|
||||
lock (ledLock)
|
||||
{
|
||||
ButtonLEDPin.Write(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void StopAlerts()
|
||||
{
|
||||
lock (ledLock)
|
||||
{
|
||||
ButtonLEDPin.Write(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
219
NightScout/SocketIONightscoutDataSource.cs
Normal file
219
NightScout/SocketIONightscoutDataSource.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data.Odbc;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NightScout.Interfaces;
|
||||
using NightscoutLibrary.Configuration;
|
||||
using Quobject.EngineIoClientDotNet.Client.Transports;
|
||||
using Quobject.SocketIoClientDotNet.Client;
|
||||
|
||||
namespace NightScout
|
||||
{
|
||||
public class NightscoutDataSource : INightscoutDataSource
|
||||
{
|
||||
public Socket Socket { get; set; }
|
||||
public Manager Manager { get; set; }
|
||||
public log4net.ILog Logger { get; set; }
|
||||
public IRaspberryPiButtonSource ButtonSource { get; set; }
|
||||
public INightscoutAlertConfiguration NightscoutAlertConfiguration { get; set; }
|
||||
public event Action Connected;
|
||||
public event Action<Object> DataUpdate;
|
||||
public event Action<Object> SocketError;
|
||||
|
||||
public event Action<Object> Alarm;
|
||||
public event Action<Object> UrgentAlarm;
|
||||
public event Action<Object> ClearAlarm;
|
||||
public event Action StaleDataAlarm;
|
||||
|
||||
private DateTime lastDataUpdate = DateTime.Now;
|
||||
private DateTime lastSgvReading = DateTime.Now;
|
||||
|
||||
public NightscoutDataSource(INightscoutAlertConfiguration configuration, log4net.ILog logger)
|
||||
{
|
||||
Logger = logger;
|
||||
NightscoutAlertConfiguration = configuration;
|
||||
ResetManagerAndConnect();
|
||||
PrepareSocketEvents();
|
||||
}
|
||||
|
||||
public NightscoutDataSource(INightscoutAlertConfiguration configuration, log4net.ILog logger, IRaspberryPiButtonSource buttonSource)
|
||||
: this(configuration, logger)
|
||||
{
|
||||
ButtonSource = buttonSource;
|
||||
ButtonSource.ButtonStateChange += ButtonSource_ButtonStateChange;
|
||||
}
|
||||
|
||||
public void Emit(String eventName, String data)
|
||||
{
|
||||
Socket.Emit(eventName, data);
|
||||
}
|
||||
|
||||
public void Emit(String eventName, JObject data)
|
||||
{
|
||||
Socket.Emit(eventName,data);
|
||||
}
|
||||
|
||||
public virtual void Authorize()
|
||||
{
|
||||
JObject authRequest = new JObject {{"client", "web"}};
|
||||
|
||||
Socket.Emit("authorize", authRequest);
|
||||
}
|
||||
|
||||
public virtual void ClearAlerts()
|
||||
{
|
||||
Logger.Info("Sending Clear Alerts Message");
|
||||
|
||||
Socket.Emit("ack", 2, "default", 45 * 60 * 1000);
|
||||
Logger.Debug("Sent ack");
|
||||
}
|
||||
|
||||
protected virtual void OnConnect()
|
||||
{
|
||||
Logger.Info("Connected to Socket.IO endpoint");
|
||||
|
||||
if (Connected != null)
|
||||
Connected();
|
||||
}
|
||||
|
||||
protected virtual void OnDataUpdate(object data)
|
||||
{
|
||||
Logger.DebugFormat("Data Update: {0}", data);
|
||||
if (DataUpdate != null)
|
||||
DataUpdate(data);
|
||||
//Update lastUpdated
|
||||
JObject dataUpdate = JObject.Parse(data.ToString());
|
||||
if (dataUpdate["lastUpdated"] != null)
|
||||
{ //lastUpdated is in ms
|
||||
Int32 lastUpdatedUnixTime = (Int32)(dataUpdate["lastUpdated"].ToObject<Int64>() / 1000);
|
||||
lastDataUpdate = UnixTimeStampToDateTime(lastUpdatedUnixTime);
|
||||
Logger.InfoFormat("Last data update reset to {0}", lastDataUpdate);
|
||||
}
|
||||
if (dataUpdate["sgvs"] != null)
|
||||
{
|
||||
var sgvs = dataUpdate["sgvs"].Children();
|
||||
var newestSSgv =
|
||||
sgvs.Where(sgv => sgv["mills"] != null).OrderByDescending(sgv => sgv["mills"].Value<Int64>()).First();
|
||||
Int64 sgvReadTime = newestSSgv["mills"].Value<Int64>();
|
||||
DateTime reading = UnixTimeStampToDateTime(sgvReadTime / 1000);;
|
||||
|
||||
if (reading > lastSgvReading)
|
||||
lastSgvReading = reading;
|
||||
if(newestSSgv["mgdl"] != null)
|
||||
Logger.InfoFormat("New sgv read of {0} mg/dl on {1}", newestSSgv["mgdl"], lastSgvReading);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSocketError(object error)
|
||||
{
|
||||
//Socket.Close();
|
||||
Logger.InfoFormat("Socket Error: {0}", error);
|
||||
if (SocketError != null)
|
||||
SocketError(error);
|
||||
}
|
||||
|
||||
protected virtual void OnAlarm(object alarm)
|
||||
{
|
||||
Logger.InfoFormat("Alarm: {0}", alarm);
|
||||
if (Alarm != null)
|
||||
Alarm(alarm);
|
||||
}
|
||||
|
||||
protected virtual void OnUrgentAlarm(object alarm)
|
||||
{
|
||||
Logger.InfoFormat("Urgent Alarm: {0}", alarm);
|
||||
if (UrgentAlarm != null)
|
||||
UrgentAlarm(alarm);
|
||||
}
|
||||
protected virtual void OnClearAlarm(object alarm)
|
||||
{
|
||||
Logger.InfoFormat("Clear Alarm: {0}", alarm);
|
||||
if (ClearAlarm != null)
|
||||
ClearAlarm(alarm);
|
||||
}
|
||||
|
||||
protected virtual void OnStaleDataAlarm()
|
||||
{
|
||||
if (StaleDataAlarm != null)
|
||||
StaleDataAlarm();
|
||||
}
|
||||
|
||||
protected void ResetManagerAndConnect()
|
||||
{
|
||||
//, DisablePing = true, Transports = new List<string>() { "polling" }
|
||||
Options options;
|
||||
options = new IO.Options();
|
||||
|
||||
|
||||
|
||||
Manager = new Manager(new Uri(NightscoutAlertConfiguration.NightscoutBaseURL), options);
|
||||
|
||||
|
||||
Socket = Manager.Socket("/"); //IO.Socket(configuration.NightscoutBaseURL, options);
|
||||
}
|
||||
|
||||
private void HeartbeatThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
//30 minutes - (currentTime - lastDataUpdate)
|
||||
const double millisecondsToSleep = (5*60*1000); //(30*60*1000) - (DateTime.Now - lastDataUpdate).TotalMilliseconds;
|
||||
Thread.Sleep((Int32)millisecondsToSleep);
|
||||
if ((DateTime.Now - lastDataUpdate).TotalMinutes >= 20)
|
||||
{ //forcefully reset data connection
|
||||
Logger.Info("Data update timeout, closing socket");
|
||||
Manager.EngineSocket.Close();
|
||||
lastDataUpdate = DateTime.Now;
|
||||
}
|
||||
if ((DateTime.Now - lastSgvReading).TotalMinutes >= 30)
|
||||
{ //Stale data alarm
|
||||
OnStaleDataAlarm();
|
||||
Logger.Info("Data stale alarm");
|
||||
lastSgvReading = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void PrepareSocketEvents()
|
||||
{
|
||||
Socket.On(Socket.EVENT_CONNECT, OnConnect);
|
||||
Socket.On(Socket.EVENT_ERROR, OnSocketError);
|
||||
|
||||
Socket.On("dataUpdate", OnDataUpdate);
|
||||
|
||||
Socket.On("alarm", OnAlarm);
|
||||
Socket.On("urgent_alarm", OnUrgentAlarm);
|
||||
Socket.On("clear_alarm", OnClearAlarm);
|
||||
|
||||
Manager.On(Manager.EVENT_CONNECT_ERROR, (err) => Logger.InfoFormat("EVENT_CONNECT_ERROR: {0}",err));
|
||||
Manager.On(Manager.EVENT_ERROR, (err) => Logger.InfoFormat("EVENT_ERROR: {0}", err));
|
||||
Manager.On(Manager.EVENT_RECONNECT_ERROR, (err) => Logger.InfoFormat("EVENT_RECONNECT_ERROR: {0}", err));
|
||||
Manager.On(Manager.EVENT_RECONNECT_FAILED, () => Logger.Info("EVENT_RECONNECT_FAILED"));
|
||||
Manager.On(Manager.EVENT_CLOSE, (reason) => Logger.InfoFormat("EVENT_CLOSE: {0}", reason));
|
||||
|
||||
Task.Factory.StartNew(HeartbeatThread,TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
private void ButtonSource_ButtonStateChange(bool obj)
|
||||
{
|
||||
if (obj)
|
||||
{ //Button pressed, STOP active alerts
|
||||
ClearAlerts();
|
||||
}
|
||||
}
|
||||
|
||||
private static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
|
||||
{
|
||||
// Unix timestamp is seconds past epoch
|
||||
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||
return dtDateTime;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
5
NightScout/packages.config
Normal file
5
NightScout/packages.config
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="log4net" version="2.0.8" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="11.0.1" targetFramework="net40" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user