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; /// /// 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. /// public abstract class RelayDevice { /// /// A thread-safe dictionary to store the status of each relay outlet. /// private readonly ConcurrentDictionary _relaysStatus = new(); /// /// 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. /// private readonly Timer? _timer; /// /// The Relay object representing the relay device. This object contains information about the relay, such as its name, type, and other relevant details. /// public readonly Relay Relay; /// /// 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. /// public readonly RelaySettings RelaySettings; //string host, int port, int relays, int? refreshTime, EventHandler refreshEvent /// /// 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. /// /// The Relay object representing the relay device. /// The RelaySettings object containing the configuration settings for the relay device. 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(); } } /// /// 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. /// public event EventHandler? RelayStatusChanged; /// /// 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. /// /// public abstract bool CheckDevice(); /// /// 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. /// public abstract void CheckStatus(); /// /// 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. /// /// public abstract bool GetStatusRelay(); /// /// 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. /// /// public abstract Task GetStatusRelayAsync(); /// /// 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. /// /// The ID of the relay outlet. /// The status of the specified relay outlet. public virtual RelayEnum.Status GetStatusRelay(int outletId) { lock (_relaysStatus) { return _relaysStatus.GetValueOrDefault(outletId, RelayEnum.Status.Unknown); } } /// /// 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. /// /// The ID of the relay outlet. /// The new status of the relay outlet. 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; } } /// /// 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. /// /// The ID of the relay outlet. /// The duration in milliseconds for which the relay outlet should be powered off. public virtual void PowerOnOffRelay(int outletId, int milliseconds) { Task.Run(() => { PowerOffRelay(outletId); Task.Delay(milliseconds); PowerOnRelay(outletId); }); } /// /// 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. /// public virtual void Refresh() { } /// /// 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. /// /// The ID of the relay outlet to power on. public abstract void PowerOnRelay(int outletId); /// /// 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. /// /// The ID of the relay outlet to power off. public abstract void PowerOffRelay(int outletId); /// /// 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. /// public abstract void PowerOnAll(); /// /// 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. /// public abstract void PowerOffAll(); /// /// 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. /// /// public abstract void RebootOutlet(int outletId); /// /// Reboots all relay outlets. This method is abstract and must be implemented by derived classes to provide specific functionality for rebooting all relay outlets. /// public abstract void Reboot(); }