Implemented reminders to clear alarm state after 15 seconds

Signed-off-by: Paul Yuknewicz <paulyuk@Pauls-MBP-2.lan>
This commit is contained in:
Paul Yuknewicz 2023-05-22 10:53:12 -07:00
parent a3b93d848e
commit 702bbcdc81
6 changed files with 49 additions and 26 deletions

View File

@ -90,16 +90,12 @@ Expected output:
When you ran the client app: When you ran the client app:
1. A `SmartDetectorActor` is created with these properties: Id = 1, Location = "First Floor", Status = "Ready". 1. Two `SmartDetectorActor` actors are created and initialized with Id, Location, and Status="Ready"
2. Another `SmartDetectorActor` is created with these properties: Id = 2, Location = "Second Floor", Status = "Ready". 2. The `DetectSmokeAsync` method of `SmartDetectorActor` 1 is called.
3. The status of `SmartDetectorActor` 1 is read and printed to the console. 3. The `TriggerAlarmForAllDetectors` method of `ControllerActor` is called.
4. The status of `SmartDetectorActor` 2 is read and printed to the console. 4. The `SoundAlarm` methods of `SmartDetectorActor` 1 and 2 are called.
5. The `DetectSmokeAsync` method of `SmartDetectorActor` 1 is called. 5. The `ControllerActor` also creates a reminder to `ClearAlarm` after 15 seconds using `RegisterReminderAsync`
6. The `TriggerAlarmForAllDetectors` method of `ControllerActor` is called.
7. The `SoundAlarm` method of `SmartDetectorActor` 1 is called.
8. The `SoundAlarm` method of `SmartDetectorActor` 2 is called.
9. The status of `SmartDetectorActor` 1 is read and printed to the console.
10. The status of `SmartDetectorActor` 2 is read and printed to the console.
Looking at the code, `SmartDetectorActor` objects are created in the client application and initialized with object state with `ActorProxy.Create<ISmartDevice>(actorId, actorType)` and then `proxySmartDevice.SetDataAsync(data)`. These objects are re-entrant and will hold on to the state as shown by `proxySmartDevice.GetDataAsync()`. Looking at the code, `SmartDetectorActor` objects are created in the client application and initialized with object state with `ActorProxy.Create<ISmartDevice>(actorId, actorType)` and then `proxySmartDevice.SetDataAsync(data)`. These objects are re-entrant and will hold on to the state as shown by `proxySmartDevice.GetDataAsync()`.
@ -144,6 +140,25 @@ The `ControllerActor` object is used to keep track of the devices and trigger th
Console.WriteLine($"Registered devices: {string.Join(", " , deviceIds)}"); Console.WriteLine($"Registered devices: {string.Join(", " , deviceIds)}");
``` ```
The `ControllerActor` internally triggers all alarms when smoke is detected, and then sets a reminder to clear all alarm states after 15 seconds.
```csharp
public async Task TriggerAlarmForAllDetectors()
{
var deviceIds = await ListRegisteredDeviceIdsAsync();
foreach (var deviceId in deviceIds)
{
// Sound the alarm on all devices
var actorId = new ActorId(deviceId);
var proxySmartDevice = ProxyFactory.CreateActorProxy<ISmartDevice>(actorId, "SmokeDetectorActor");
await proxySmartDevice.SoundAlarm();
}
// Register a reminder to refresh and clear alarm state every 15 seconds
await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
}
```
Additionally look at: Additionally look at:
- `SmartDevice.Service/SmartDetectorActor.cs` which contains the implementation of the the smart device actor actions - `SmartDevice.Service/SmartDetectorActor.cs` which contains the implementation of the the smart device actor actions

View File

@ -57,9 +57,6 @@ class Program
var controllerActorId = new ActorId("controller"); var controllerActorId = new ActorId("controller");
var proxyController = ActorProxy.Create<IController>(controllerActorId, controllerActorType); var proxyController = ActorProxy.Create<IController>(controllerActorId, controllerActorType);
//Register reminders every 30 to clear out invalid state or alarms
await proxyController.RegisterReminder();
Console.WriteLine($"Registering the IDs of both Devices..."); Console.WriteLine($"Registering the IDs of both Devices...");
await proxyController.RegisterDeviceIdsAsync(new string[]{deviceId1, deviceId2}); await proxyController.RegisterDeviceIdsAsync(new string[]{deviceId1, deviceId2});
var deviceIds = await proxyController.ListRegisteredDeviceIdsAsync(); var deviceIds = await proxyController.ListRegisteredDeviceIdsAsync();
@ -77,8 +74,8 @@ class Program
Console.WriteLine($"Device 2 state: {storedDeviceData2}"); Console.WriteLine($"Device 2 state: {storedDeviceData2}");
// Sleep for 35 seconds and observe reminders have cleared alarm state // Sleep for 35 seconds and observe reminders have cleared alarm state
Console.WriteLine("Sleeping for 35 seconds before observing alarm state after reminders fire"); Console.WriteLine("Sleeping for 16 seconds before checking status again to see reminders fire and clear alarms");
await Task.Delay(35000); await Task.Delay(16000);
storedDeviceData1 = await proxySmartDevice1.GetDataAsync(); storedDeviceData1 = await proxySmartDevice1.GetDataAsync();
Console.WriteLine($"Device 1 state: {storedDeviceData1}"); Console.WriteLine($"Device 1 state: {storedDeviceData1}");

View File

@ -6,12 +6,6 @@ public interface IController : IActor
Task RegisterDeviceIdsAsync(string[] deviceIds); Task RegisterDeviceIdsAsync(string[] deviceIds);
Task<string[]> ListRegisteredDeviceIdsAsync(); Task<string[]> ListRegisteredDeviceIdsAsync();
Task TriggerAlarmForAllDetectors(); Task TriggerAlarmForAllDetectors();
/// <summary>
/// Registers a timer.
/// </summary>
/// <returns>A task that represents the asynchronous save operation.</returns>
Task RegisterReminder();
} }
public class ControllerData public class ControllerData

View File

@ -7,6 +7,7 @@ public interface ISmartDevice : IActor
Task<SmartDeviceData> GetDataAsync(); Task<SmartDeviceData> GetDataAsync();
Task DetectSmokeAsync(); Task DetectSmokeAsync();
Task SoundAlarm(); Task SoundAlarm();
Task ClearAlarm();
} }
public class SmartDeviceData public class SmartDeviceData

View File

@ -4,7 +4,7 @@ using SmartDevice.Interfaces;
namespace SmartDevice; namespace SmartDevice;
internal class ControllerActor : Actor, IController internal class ControllerActor : Actor, IController, IRemindable
{ {
private readonly string deviceIdsKey = "device-ids"; private readonly string deviceIdsKey = "device-ids";
@ -60,12 +60,21 @@ internal class ControllerActor : Actor, IController
var proxySmartDevice = ProxyFactory.CreateActorProxy<ISmartDevice>(actorId, "SmokeDetectorActor"); var proxySmartDevice = ProxyFactory.CreateActorProxy<ISmartDevice>(actorId, "SmokeDetectorActor");
await proxySmartDevice.SoundAlarm(); await proxySmartDevice.SoundAlarm();
} }
// Register a reminder to refresh and clear alarm state every 15 seconds
await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
} }
public async Task RegisterReminder() public async Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period)
{ {
// Register a reminder to refresh alarm state every 30 seconds if (reminderName == "AlarmRefreshReminder") {
await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(30)); var deviceIds = await ListRegisteredDeviceIdsAsync();
foreach (var deviceId in deviceIds)
{
var actorId = new ActorId(deviceId);
var proxySmartDevice = ProxyFactory.CreateActorProxy<ISmartDevice>(actorId, "SmokeDetectorActor");
await proxySmartDevice.ClearAlarm();
}
}
} }
} }

View File

@ -81,4 +81,11 @@ internal class SmokeDetectorActor : Actor, ISmartDevice
smartDeviceData.Status = "Alarm"; smartDeviceData.Status = "Alarm";
await SetDataAsync(smartDeviceData); await SetDataAsync(smartDeviceData);
} }
public async Task ClearAlarm()
{
var smartDeviceData = await GetDataAsync();
smartDeviceData.Status = "Ready";
await SetDataAsync(smartDeviceData);
}
} }