Skip to content

Commit 564dab8

Browse files
authored
Added StateChanges and StateChangesWithCurrent to ILight. (#192)
1 parent 3a90a5b commit 564dab8

6 files changed

Lines changed: 66 additions & 8 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace CodeCasa.Abstractions;
2+
3+
/// <summary>
4+
/// Represents a change in state for an entity.
5+
/// </summary>
6+
/// <typeparam name="TEntity">The type of the entity.</typeparam>
7+
/// <typeparam name="TState">The type of the state.</typeparam>
8+
/// <param name="Entity">The entity whose state changed.</param>
9+
/// <param name="Old">The old state.</param>
10+
/// <param name="New">The new state.</param>
11+
public record StateChange<TEntity, TState>(TEntity Entity, TState? Old, TState? New);

src/CodeCasa.AutomationPipelines.Lights/ReactiveNode/ILightTransitionReactiveNodeConfigurator.Toggle.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public partial interface ILightTransitionReactiveNodeConfigurator
99
/// <summary>
1010
/// Adds a time-based toggle trigger that switches between the specified light parameters when triggered by <paramref name="triggerObservable"/>.
1111
/// Quick consecutive triggers advance through all parameter sets sequentially. After a timeout period, the next trigger restarts from the beginning.
12+
/// If the light is currently on, the first trigger will turn it off.
1213
/// </summary>
1314
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
1415
/// <param name="triggerObservable">The observable that triggers toggling to the next parameters.</param>
@@ -20,6 +21,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
2021
/// <summary>
2122
/// Adds a time-based toggle trigger that switches between the specified light parameters when triggered by <paramref name="triggerObservable"/>.
2223
/// Quick consecutive triggers advance through all parameter sets sequentially. After a timeout period, the next trigger restarts from the beginning.
24+
/// If the light is currently on, the first trigger will turn it off.
2325
/// </summary>
2426
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
2527
/// <param name="triggerObservable">The observable that triggers toggling to the next parameters.</param>
@@ -31,6 +33,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
3133
/// <summary>
3234
/// Adds a time-based toggle trigger that switches between the specified light transitions when triggered by <paramref name="triggerObservable"/>.
3335
/// Quick consecutive triggers advance through all transitions sequentially. After a timeout period, the next trigger restarts from the beginning.
36+
/// If the light is currently on, the first trigger will turn it off.
3437
/// </summary>
3538
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
3639
/// <param name="triggerObservable">The observable that triggers toggling to the next transition.</param>
@@ -42,6 +45,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
4245
/// <summary>
4346
/// Adds a time-based toggle trigger that switches between the specified light transitions when triggered by <paramref name="triggerObservable"/>.
4447
/// Quick consecutive triggers advance through all transitions sequentially. After a timeout period, the next trigger restarts from the beginning.
48+
/// If the light is currently on, the first trigger will turn it off.
4549
/// </summary>
4650
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
4751
/// <param name="triggerObservable">The observable that triggers toggling to the next transition.</param>
@@ -53,6 +57,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
5357
/// <summary>
5458
/// Adds a time-based toggle trigger that switches between nodes created by the specified factory functions when triggered by <paramref name="triggerObservable"/>.
5559
/// Quick consecutive triggers advance through all node factories sequentially. After a timeout period, the next trigger restarts from the beginning.
60+
/// If the light is currently on, the first trigger will turn it off.
5661
/// </summary>
5762
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
5863
/// <param name="triggerObservable">The observable that triggers toggling to the next node.</param>
@@ -64,6 +69,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
6469
/// <summary>
6570
/// Adds a time-based toggle trigger that switches between nodes created by the specified factory functions when triggered by <paramref name="triggerObservable"/>.
6671
/// Quick consecutive triggers advance through all node factories sequentially. After a timeout period, the next trigger restarts from the beginning.
72+
/// If the light is currently on, the first trigger will turn it off.
6773
/// </summary>
6874
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
6975
/// <param name="triggerObservable">The observable that triggers toggling to the next node.</param>
@@ -75,6 +81,7 @@ ILightTransitionReactiveNodeConfigurator AddToggle<T>(IObservable<T> triggerObse
7581
/// <summary>
7682
/// Adds a time-based toggle trigger configured by the specified <paramref name="configure"/> action when triggered by <paramref name="triggerObservable"/>.
7783
/// Quick consecutive triggers advance through all configured states sequentially. After a timeout period, the next trigger restarts from the beginning.
84+
/// If the light is currently on, the first trigger will turn it off.
7885
/// </summary>
7986
/// <typeparam name="T">The type of values emitted by the trigger observable.</typeparam>
8087
/// <param name="triggerObservable">The observable that triggers toggling to the next state.</param>

src/CodeCasa.AutomationPipelines.Lights/Toggle/ILightTransitionToggleConfigurator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace CodeCasa.AutomationPipelines.Lights.Toggle
66
/// <summary>
77
/// Configurator for time-based toggle behavior. Quick consecutive triggers advance through all states sequentially.
88
/// After a timeout period, the next trigger restarts from the beginning.
9+
/// If the light is currently on, the first trigger will turn it off.
910
/// </summary>
1011
public interface ILightTransitionToggleConfigurator
1112
{
Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,43 @@
11
using CodeCasa.Lights.NetDaemon.Extensions;
22
using CodeCasa.Lights.NetDaemon.Generated;
33
using NetDaemon.HassModel.Entities;
4+
using System.Reactive.Linq;
45

56
namespace CodeCasa.Lights.NetDaemon
67
{
78
/// <summary>
89
/// Adapts a NetDaemon light entity core to the <see cref="ILight"/> interface.
910
/// </summary>
10-
public class NetDaemonLight(ILightEntityCore lightEntity) : ILight
11+
public class NetDaemonLight : ILight
1112
{
13+
private readonly LightEntity _lightEntity;
14+
15+
/// <summary>
16+
/// Adapts a NetDaemon light entity core to the <see cref="ILight"/> interface.
17+
/// </summary>
18+
public NetDaemonLight(ILightEntityCore lightEntity)
19+
{
20+
_lightEntity = new LightEntity(lightEntity);
21+
}
22+
1223
/// <summary>
1324
/// Gets the unique identifier for this light entity.
1425
/// </summary>
15-
public string Id => lightEntity.EntityId;
26+
public string Id => _lightEntity.EntityId;
1627

1728
/// <summary>
1829
/// Gets the current parameters of the light entity.
1930
/// </summary>
2031
/// <returns>A <see cref="LightParameters"/> object representing the current state of the light.</returns>
21-
public LightParameters GetParameters() => lightEntity.GetLightParameters();
32+
public LightParameters GetParameters() => _lightEntity.GetLightParameters();
2233

2334
/// <summary>
2435
/// Applies a light transition to this light entity.
2536
/// </summary>
2637
/// <param name="transition">The transition to apply to the light.</param>
2738
public void ApplyTransition(LightTransition transition)
2839
{
29-
lightEntity.ApplyTransition(transition);
40+
_lightEntity.ApplyTransition(transition);
3041
}
3142

3243
/// <summary>
@@ -35,20 +46,30 @@ public void ApplyTransition(LightTransition transition)
3546
/// <returns>An array of child light entities wrapped as <see cref="ILight"/> instances, or an empty array if this light has no children.</returns>
3647
public ILight[] GetChildren()
3748
{
38-
var childEntityIds = new LightEntity(lightEntity).Attributes?.EntityId;
49+
var childEntityIds = new LightEntity(_lightEntity).Attributes?.EntityId;
3950
if (childEntityIds == null || !childEntityIds.Any())
4051
{
4152
return [];
4253
}
4354
return childEntityIds.Select(id =>
4455
{
4556
// A group light may include itself in its list of children; avoid infinite recursion by returning this instance.
46-
if (id == lightEntity.EntityId)
57+
if (id == _lightEntity.EntityId)
4758
{
4859
return this;
4960
}
50-
return new NetDaemonLight(new LightEntity(lightEntity.HaContext, id));
61+
return new NetDaemonLight(new LightEntity(_lightEntity.HaContext, id));
5162
}).ToArray<ILight>();
5263
}
64+
65+
/// <inheritdoc/>
66+
public IObservable<Abstractions.StateChange<ILight, LightParameters>> StateChanges() =>
67+
_lightEntity.StateChanges().Select(sc => new Abstractions.StateChange<ILight, LightParameters>(this,
68+
sc.Old?.Attributes?.ToLightParameters(), sc.New?.Attributes?.ToLightParameters()));
69+
70+
/// <inheritdoc/>
71+
public IObservable<Abstractions.StateChange<ILight, LightParameters>> StateChangesWithCurrent() =>
72+
_lightEntity.StateChangesWithCurrent().Select(sc => new Abstractions.StateChange<ILight, LightParameters>(this,
73+
sc.Old?.Attributes?.ToLightParameters(), sc.New?.Attributes?.ToLightParameters()));
5374
}
5475
}

src/CodeCasa.Lights/CodeCasa.Lights.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,9 @@
3232
<PackagePath>\</PackagePath>
3333
</None>
3434
</ItemGroup>
35+
36+
<ItemGroup>
37+
<ProjectReference Include="..\CodeCasa.Abstractions\CodeCasa.Abstractions.csproj" />
38+
</ItemGroup>
3539

3640
</Project>

src/CodeCasa.Lights/ILight.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace CodeCasa.Lights;
1+
using CodeCasa.Abstractions;
2+
3+
namespace CodeCasa.Lights;
24

35
/// <summary>
46
/// Represents a single light or group of lights.
@@ -26,4 +28,16 @@ public interface ILight
2628
/// </summary>
2729
/// <returns>An array of child lights, or an empty array if this light has no children.</returns>
2830
ILight[] GetChildren();
31+
32+
/// <summary>
33+
/// Returns an observable that emits notifications when the state of the light changes.
34+
/// </summary>
35+
/// <returns>An <see cref="IObservable{T}"/> that emits <see cref="StateChange{ILight, LightParameters}"/> events.</returns>
36+
IObservable<StateChange<ILight, LightParameters>> StateChanges();
37+
38+
/// <summary>
39+
/// Returns an observable that emits the current state and then notifications when the state of the light changes.
40+
/// </summary>
41+
/// <returns>An <see cref="IObservable{T}"/> that emits <see cref="StateChange{ILight, LightParameters}"/> events.</returns>
42+
IObservable<StateChange<ILight, LightParameters>> StateChangesWithCurrent();
2943
}

0 commit comments

Comments
 (0)