198 lines
10 KiB
C#
198 lines
10 KiB
C#
using System.Collections.Concurrent;
|
|
using adas_core.Domain.Enums;
|
|
using adas_core.Domain.Models.MongoModels;
|
|
using adas_core.module.Relays.Models;
|
|
using Timer = System.Timers.Timer;
|
|
|
|
namespace adas_core.module.Relays.Devices;
|
|
|
|
/// <summary>
|
|
/// Abstract class representing a relay device.
|
|
/// It provides methods to check the device status, get and set the status of individual relays, and control the power state of the relays.
|
|
/// The class also includes an event to notify when the status of a relay changes.
|
|
/// The implementation of the methods is left to the derived classes, which will provide specific functionality based on the type of relay device being used.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=d49d435 -->
|
|
public abstract class RelayDevice
|
|
{
|
|
/// <summary>
|
|
/// A thread-safe dictionary to store the status of each relay outlet.
|
|
/// </summary>
|
|
private readonly ConcurrentDictionary<int, RelayEnum.Status> _relaysStatus = new();
|
|
|
|
/// <summary>
|
|
/// A timer to periodically check the status of the relay device. The timer is initialized based on the refresh time specified in the relay settings.
|
|
/// If the refresh time is greater than 0, the timer will trigger the CheckStatus method at regular intervals to update the status of the relays.
|
|
/// </summary>
|
|
private readonly Timer? _timer;
|
|
|
|
/// <summary>
|
|
/// The Relay object representing the relay device. This object contains information about the relay, such as its name, type, and other relevant details.
|
|
/// </summary>
|
|
public readonly Relay Relay;
|
|
|
|
/// <summary>
|
|
/// The RelaySettings object containing the configuration settings for the relay device.
|
|
/// This includes parameters such as the refresh time for checking the status of the relays, and any other settings that may be relevant for the operation of the relay device.
|
|
/// </summary>
|
|
public readonly RelaySettings RelaySettings;
|
|
|
|
//string host, int port, int relays, int? refreshTime, EventHandler refreshEvent
|
|
/// <summary>
|
|
/// Constructor for the RelayDevice class. It initializes the Relay and RelaySettings properties, and sets up the timer for checking the status of the relays if a refresh time is specified in the relay settings.
|
|
/// </summary>
|
|
/// <param name="relay">The Relay object representing the relay device.</param>
|
|
/// <param name="relaySettings">The RelaySettings object containing the configuration settings for the relay device.</param>
|
|
/// <!-- aidoc:v1 sig=4036497 body=4a2098e -->
|
|
protected RelayDevice(Relay relay, RelaySettings relaySettings)
|
|
{
|
|
Relay = relay;
|
|
RelaySettings = relaySettings;
|
|
if (relaySettings.RefreshTime is > 0)
|
|
{
|
|
_timer = new Timer();
|
|
_timer.Interval = relaySettings.RefreshTime.Value * 1000;
|
|
_timer.Elapsed += delegate
|
|
{
|
|
_timer.Stop();
|
|
CheckStatus();
|
|
_timer.Start();
|
|
};
|
|
_timer.Start();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event that is triggered when the status of a relay changes. The event handler receives the instance of the RelayDevice and the outlet ID of the relay that changed its status.
|
|
/// </summary>
|
|
public event EventHandler<int>? RelayStatusChanged;
|
|
|
|
/// <summary>
|
|
/// Checks the status of the relay device. This method is abstract and must be implemented by derived classes to provide specific functionality for checking the status of the relay device.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
|
/// "The <returns> tag is empty; the method returns a bool but its meaning (e.g., true = device OK/connected, false = fault/not found) is not documented." -->
|
|
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
|
|
/// "The summary specifies 'relay device', but the code (CheckDevice) and signature provide no evidence the device is a relay; the term appears to be an unsupported assumption." -->
|
|
public abstract bool CheckDevice();
|
|
|
|
/// <summary>
|
|
/// Checks the status of the relays. This method is abstract and must be implemented by derived classes to provide specific functionality for checking the status of the relays.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=7c1569a -->
|
|
public abstract void CheckStatus();
|
|
|
|
/// <summary>
|
|
/// Gets the status of the relay device. This method is abstract and must be implemented by derived classes to provide specific functionality for retrieving the status of the relay device.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
|
/// "The <returns> tag is empty; the method returns a bool indicating the relay status, which is not described." -->
|
|
public abstract bool GetStatusRelay();
|
|
|
|
/// <summary>
|
|
/// Gets the status of the relays. This method is abstract and must be implemented by derived classes to provide specific functionality for retrieving the status of the relays.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <!-- aidoc-review:v1 severity=low kind=missing_returns
|
|
/// "The <returns> tag is empty and does not describe what the Task<bool> return value represents." -->
|
|
public abstract Task<bool> GetStatusRelayAsync();
|
|
|
|
/// <summary>
|
|
/// Gets the status of a specific relay outlet. This method retrieves the status of the relay outlet with the specified outlet ID from the _relaysStatus dictionary.
|
|
/// </summary>
|
|
/// <param name="outletId">The ID of the relay outlet.</param>
|
|
/// <returns>The status of the specified relay outlet.</returns>
|
|
/// <!-- aidoc:v1 sig=72e92a5 body=80cb7be -->
|
|
public virtual RelayEnum.Status GetStatusRelay(int outletId)
|
|
{
|
|
lock (_relaysStatus)
|
|
{
|
|
return _relaysStatus.GetValueOrDefault(outletId, RelayEnum.Status.Unknown);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the status of a specific relay outlet. This method updates the status of the relay outlet with the specified outlet ID in the _relaysStatus dictionary.
|
|
/// </summary>
|
|
/// <param name="outletId">The ID of the relay outlet.</param>
|
|
/// <param name="status">The new status of the relay outlet.</param>
|
|
/// <!-- aidoc:v1 sig=82b3cca body=3d9883a -->
|
|
public virtual void SetStatusRelay(int outletId, RelayEnum.Status status)
|
|
{
|
|
lock (_relaysStatus)
|
|
{
|
|
if (!_relaysStatus.ContainsKey(outletId) || _relaysStatus[outletId] != status)
|
|
RelayStatusChanged?.Invoke(this, outletId);
|
|
_relaysStatus[outletId] = status;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Powers on or off a specific relay outlet for a specified duration.
|
|
/// This method first powers off the relay outlet with the specified outlet ID, then waits for the specified number of milliseconds, and finally powers on the relay outlet again.
|
|
/// The method runs asynchronously to avoid blocking the main thread while waiting for the specified duration.
|
|
/// </summary>
|
|
/// <param name="outletId">The ID of the relay outlet.</param>
|
|
/// <param name="milliseconds">The duration in milliseconds for which the relay outlet should be powered off.</param>
|
|
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
|
/// "The summary states the method 'waits' for the specified milliseconds between PowerOffRelay and PowerOnRelay, but Task.Delay's returned Task is not awaited, so PowerOnRelay runs immediately after PowerOffRelay with no actual delay." -->
|
|
public virtual void PowerOnOffRelay(int outletId, int milliseconds)
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
PowerOffRelay(outletId);
|
|
Task.Delay(milliseconds);
|
|
PowerOnRelay(outletId);
|
|
});
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Refreshes the status of the relay device. This method is virtual and can be overridden by derived classes to provide specific functionality for refreshing the status of the relay device.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=d883f16 body=4448e1d -->
|
|
public virtual void Refresh()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Powers on a specific relay outlet. This method is abstract and must be implemented by derived classes to provide specific functionality for powering on a relay outlet with the specified outlet ID.
|
|
/// </summary>
|
|
/// <param name="outletId">The ID of the relay outlet to power on.</param>
|
|
/// <!-- aidoc:v1 sig=d94c874 -->
|
|
public abstract void PowerOnRelay(int outletId);
|
|
|
|
/// <summary>
|
|
/// Powers off a specific relay outlet. This method is abstract and must be implemented by derived classes to provide specific functionality for powering off a relay outlet with the specified outlet ID.
|
|
/// </summary>
|
|
/// <param name="outletId">The ID of the relay outlet to power off.</param>
|
|
/// <!-- aidoc:v1 sig=5394819 -->
|
|
public abstract void PowerOffRelay(int outletId);
|
|
|
|
/// <summary>
|
|
/// Powers on all relay outlets. This method is abstract and must be implemented by derived classes to provide specific functionality for powering on all relay outlets.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=c996518 -->
|
|
public abstract void PowerOnAll();
|
|
|
|
/// <summary>
|
|
/// Powers off all relay outlets. This method is abstract and must be implemented by derived classes to provide specific functionality for powering off all relay outlets.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=489ea3b -->
|
|
public abstract void PowerOffAll();
|
|
|
|
/// <summary>
|
|
/// Reboots a specific relay outlet. This method is abstract and must be implemented by derived classes to provide specific functionality for rebooting a relay outlet with the specified outlet ID.
|
|
/// </summary>
|
|
/// <param name="outletId"></param>
|
|
/// <!-- aidoc:v1 sig=a3e578d -->
|
|
public abstract void RebootOutlet(int outletId);
|
|
|
|
/// <summary>
|
|
/// Reboots all relay outlets. This method is abstract and must be implemented by derived classes to provide specific functionality for rebooting all relay outlets.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=4b9c90f -->
|
|
public abstract void Reboot();
|
|
} |