Skip to content

Commit

Permalink
Merge pull request #4 from AmadeusW/addLatching
Browse files Browse the repository at this point in the history
Add latching
  • Loading branch information
AmadeusW authored Dec 10, 2019
2 parents a99e722 + 6fc43dc commit 6e087f6
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 14 deletions.
30 changes: 26 additions & 4 deletions ConfigurationReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class ConfigurationReader
private readonly string configurationFileName;
internal string Url { get; private set; }
internal string Token { get; private set; }
internal int Poll { get; private set; }
internal int Latch { get; private set; }
internal bool Initialized { get; private set; }

internal ConfigurationReader(string configurationFileName)
Expand Down Expand Up @@ -36,15 +38,18 @@ internal void Initialize()
File.WriteAllText(this.configurationFileName,
@"url: http://host:8123/api/states/sensor.media # URL of the API endpoint. See https://developers.home-assistant.io/docs/en/external_api_rest.html
token: InsertLongTermTokenHere # Home Assistant long term token
poll: 250 # Polling delay in milliseconds. This represents delay between calls to the OS.
latch: 1000 # Latching delay in milliseconds. This represents duration of how long media state must be steady before making API call
");
Initialized = false;
}
}

private bool ReadConfiguration()
{
bool gotUrl = false;
bool gotToken = false;
bool gotUrl, gotToken, gotPoll, gotLatch;
gotUrl = gotToken = gotPoll = gotLatch = false;

var lines = File.ReadAllLines(this.configurationFileName);
foreach (var line in lines)
{
Expand All @@ -60,12 +65,29 @@ private bool ReadConfiguration()
Token = value;
gotToken = true;
break;
case "poll":
Poll = Int32.Parse(value);
gotPoll = true;
break;
case "latch":
Latch = Int32.Parse(value);
gotLatch = true;
break;
}

if (gotUrl && gotToken)
if (gotUrl && gotToken && gotPoll && gotLatch)
return true;
}
throw new Exception("Configuration did not contain url or token");

if (!gotUrl)
throw new ApplicationException("Configuration did not contain key: url");
if (!gotToken)
throw new ApplicationException("Configuration did not contain key: token");
if (!gotPoll)
throw new ApplicationException("Configuration did not contain key: poll");
if (!gotLatch)
throw new ApplicationException("Configuration did not contain key: latch");
return false;
}

private (string, string) GetBeforeAndAfter(string text, char separator)
Expand Down
1 change: 1 addition & 0 deletions MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public MainWindow()
throw new InvalidOperationException($"Please update {configurationFileName}");
}
this.ApiEndpoint.Initialize(this.Configuration);
this.Sensor.Initialize(this.Configuration);
ConnectUiUpdates();

// Set initial UI and make initial request
Expand Down
6 changes: 6 additions & 0 deletions MediaSensor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<Version>1.1.0</Version>
<Authors>Amadeusz Wieczorek</Authors>
<Company>Amadeusz Wieczorek</Company>
<RepositoryUrl>https://github.com/AmadeusW/homeautomation-mediasensor</RepositoryUrl>
<ApplicationIcon>play.ico</ApplicationIcon>
<Win32Resource />
</PropertyGroup>

</Project>
69 changes: 59 additions & 10 deletions Sensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,89 @@ namespace MediaSensor
/// </summary>
internal class Sensor : IDisposable
{
/// <summary>
/// Latched value of sensor state
/// </summary>
internal MediaState CurrentState { get; private set; }

/// <summary>
/// Fired when <see cref="CurrentState"/> changes
/// </summary>
internal event EventHandler<SensorStateEventArgs> StateChanged;
private Timer Timer { get; }

/// <summary>
/// Immediate value of sensor state
/// </summary>
private MediaState TransientState { get; set; }

private Timer SensorTimer { get; set; }
public Timer LatchTimer { get; private set; }
private bool Initialized { get; set; }

internal Sensor()
{
this.Timer = new Timer(500);
this.Timer.Elapsed += OnTimerElapsed;
}

internal void Initialize(ConfigurationReader configuration)
{
this.SensorTimer = new Timer(configuration.Poll);
this.SensorTimer.Elapsed += OnPollingDelayElapsed;
this.LatchTimer = new Timer(configuration.Latch);
this.LatchTimer.AutoReset = false;
this.LatchTimer.Elapsed += OnLatchingDelayElapsed;
this.Initialized = true;
}

internal void Start()
{
this.Timer.Start();
if (this.Initialized)
{
this.SensorTimer.Start();
}
}

internal void Stop()
{
this.Timer.Stop();
if (this.Initialized)
{
this.SensorTimer.Stop();
this.LatchTimer.Stop();
}
}

public void Dispose()
{
Timer.Stop();
Timer.Elapsed -= OnTimerElapsed;
SensorTimer.Stop();
SensorTimer.Elapsed -= OnPollingDelayElapsed;
LatchTimer.Stop();
LatchTimer.Elapsed -= OnLatchingDelayElapsed;
}

private void OnTimerElapsed(object sender, ElapsedEventArgs e)
private void OnPollingDelayElapsed(object sender, ElapsedEventArgs e)
{
var newState = SensorCore.GetState();
if (newState != CurrentState)
if (newState != TransientState)
{
CurrentState = newState;
TransientState = newState;
LatchTimer.Stop(); // Reset the latch timer
LatchTimer.Start();
}
}

private void OnLatchingDelayElapsed(object sender, ElapsedEventArgs e)
{
// If state has changed during latching delay, this timer would have been reset
// and would not have elapsed.
// If we're running this code, it means that the transient value has not changed.
if (CurrentState != TransientState)
{
CurrentState = TransientState;
StateChanged?.Invoke(this, new SensorStateEventArgs(CurrentState));
}
else
{
// We just averted a glitch
}
}
}

Expand Down
Binary file added play.ico
Binary file not shown.

0 comments on commit 6e087f6

Please sign in to comment.