Skip to content

Commit

Permalink
feat: updates to allow telnet communication and handle login sequence…
Browse files Browse the repository at this point in the history
…. Updates for reliability and performance
  • Loading branch information
ndorin committed Dec 5, 2023
1 parent 5a6322a commit 32c89fd
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,4 @@ MigrationBackup/
*.projectinfo

SPlsWork/
src/Properties/ApcEpi.cplz
2 changes: 2 additions & 0 deletions src/Abstractions/IApDeviceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Queues;
using PepperDash_Essentials_Core.Devices;
using ApcEpi.Config;


namespace ApcEpi.Abstractions
Expand All @@ -18,5 +19,6 @@ public interface IApDeviceBuilder : IKeyName
EssentialsDevice Build();
bool UseEssentialsJoinMap { get; }
bool EnableAsOnline { get; }
ApDeviceConfig Config { get; }
}
}
3 changes: 3 additions & 0 deletions src/Builders/Ap89XxBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ namespace ApcEpi.Builders
{
public class Ap89XxBuilder : IApDeviceBuilder
{
public ApDeviceConfig Config { get; private set; }

private Ap89XxBuilder(string key, string name, IBasicCommunication coms, ApDeviceConfig config)
{
Coms = coms;
Name = name;
Key = key;
Config = config;

UseEssentialsJoinMap = config.UseEssentialsJoinmap;
Outlets = BuildOutletsFromConfig(key, config, coms);
Expand Down
132 changes: 103 additions & 29 deletions src/Devices/ApDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@
using PepperDash.Essentials.Core.Bridges;
using Feedback = PepperDash.Essentials.Core.Feedback;
using PepperDash_Essentials_Core.Devices;
using ApcEpi.Config;


namespace ApcEpi.Devices
{
public class ApDevice : EssentialsBridgeableDevice, IOutletName, IOutletPower, IOutletOnline, IHasControlledPowerOutlets
{
private ApDeviceConfig _config;

private readonly IBasicCommunication _comms;
private readonly string _password = "apc"; // sets default
private readonly string _username = "apc"; // sets default
private const string DELIMITER = "\r";

// Used to track the login state of telnet connections
private bool _loggedIn = false;

private readonly StatusMonitorBase _monitor;
public ReadOnlyDictionary<int, IHasPowerCycle> PduOutlets { get; private set; }
bool _useEssentialsJoinmap;
Expand All @@ -26,36 +37,78 @@ public class ApDevice : EssentialsBridgeableDevice, IOutletName, IOutletPower, I
public ApDevice(IApDeviceBuilder builder)
: base(builder.Key, builder.Name)
{
_comms = builder.Coms;
_config = builder.Config;

if (!string.IsNullOrEmpty(_config.Control.TcpSshProperties.Username))
{
_username = _config.Control.TcpSshProperties.Username;
} if (!string.IsNullOrEmpty(_config.Control.TcpSshProperties.Password))
{
_password = _config.Control.TcpSshProperties.Password;
}

Feedbacks = new FeedbackCollection<Feedback>();

PduOutlets = builder.Outlets;
//_monitor = new GenericCommunicationMonitor(
// this,
// builder.Coms,
// 30000,
// 120000,
// 240000,
// ApOutletStatusCommands.GetAllOutletStatusCommand());
_monitor = new GenericCommunicationMonitor(
this,
builder.Coms,
30000,
120000,
this,
builder.Coms,
30000,
120000,
240000,
ApOutletStatusCommands.GetAllOutletStatusCommand());
() =>
{
//Debug.Console(2, this, "Polling for status");
//Debug.Console(2, this, "Block Poll?: {0}", _config.Control.Method == eControlMethod.Tcpip && !_loggedIn);
if (_config.Control.Method == eControlMethod.Tcpip && !_loggedIn) return;
SendText(ApOutletStatusCommands.GetAllOutletStatusCommand());
});


NameFeedback = new StringFeedback("DeviceNameFeedback", () => Name);
Feedbacks.Add(IsOnline);
Feedbacks.Add(NameFeedback);
EnableAsOnline = builder.EnableAsOnline;
_useEssentialsJoinmap = builder.UseEssentialsJoinMap;

_comms.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(_comms_TextReceived);

//var loginPromptGather = new CommunicationGather(_comms, DELIMITER);
//loginPromptGather.LineReceived += _comms_TextReceived;

var gather = new CommunicationGather(builder.Coms, "\n");
gather.LineReceived +=
(o, textArgs) => ProcessResponse(PduOutlets, textArgs.Text);

/*
(o, textArgs) =>
{
if (_config.Control.Method == eControlMethod.Tcpip && !_loggedIn) return;
ProcessResponse(PduOutlets, textArgs.Text);
};

var socket = builder.Coms as ISocketStatus;
if (socket != null)
{
socket.ConnectionChange +=
(sender, args) =>
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectionStatus:{0}",
args.Client.ClientStatus.ToString());
}*/
{
if (!socket.IsConnected)
{
_loggedIn = false;
}
};
}

CrestronEnvironment.ProgramStatusEventHandler += type =>
{
Expand All @@ -64,33 +117,54 @@ public ApDevice(IApDeviceBuilder builder)
CommunicationMonitor.Stop();
};
}

DeviceManager.AllDevicesActivated += (sender, args) =>
{
try
{
builder.Coms.Connect();
CommunicationMonitor.Start();
}
catch (Exception ex)
{
Debug.Console(0,
this,
Debug.ErrorLogLevel.Error,
"Error handling all devices activated : {0}",
ex.Message);
}
};
public override void Initialize()
{
_comms.Connect();

if (_config.Control.Method == eControlMethod.Ssh)
CommunicationMonitor.Start();
}

public static void ProcessResponse(ReadOnlyDictionary<int, IHasPowerCycle> outlets, string response)
void _comms_TextReceived(object sender, GenericCommMethodReceiveTextArgs e)
{
if (e.Text.Contains("User Name"))
{
Debug.Console(2, this, "Attempting to Log in...");
SendText(_username);
return;
}
else if (e.Text.Contains("Password"))
{
SendText(_password);
return;
}
else if (e.Text.Contains("apc>"))
{
if (!_loggedIn)
Debug.Console(2, this, "Logged in Successfully.");

_loggedIn = true;
CommunicationMonitor.Start();
}
}

public void SendText(string text)
{
_comms.SendText(text + DELIMITER);
}

public void ProcessResponse(ReadOnlyDictionary<int, IHasPowerCycle> outlets, string response)
{

var responseToProcess = response.Trim().Split(new[] { ':' });
if (responseToProcess.Count() != 3)
return;

try
{

var outletIndex = Convert.ToUInt32(responseToProcess[0]);
IHasPowerCycle outlet;
if (!outlets.TryGetValue((int)outletIndex, out outlet))
Expand All @@ -116,7 +190,7 @@ public static void ProcessResponse(ReadOnlyDictionary<int, IHasPowerCycle> outle
}
catch (Exception ex)
{
Debug.Console(1, "Error processing response: {0}{1}", response, ex.Message);
Debug.Console(1, this, "Error processing response: {0}{1}", response, ex.Message);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Factories/Ap89XxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class Ap89XxFactory : EssentialsPluginDeviceFactory<ApDevice>
{
public Ap89XxFactory()
{
MinimumEssentialsFrameworkVersion = "1.11.0";
MinimumEssentialsFrameworkVersion = "1.15.0";
TypeNames = new List<string>() { "Ap89xx" };
}

Expand Down

0 comments on commit 32c89fd

Please sign in to comment.