Active ports enable communication between a controller and its downstream devices (SIOs, expansion boards). Before adding readers, inputs, or outputs to a controller, you must configure the communication port that connects to those devices. This is a critical step in controller setup.
| Concept | Description |
|---|---|
| Active Port | The communication port currently enabled for downstream communication |
| Driver Number | Unique identifier for each port on the controller |
| Internal Port | Built-in port on controllers like EP1501 for direct reader connection |
| Network Port | IP-based communication (e.g., OSDP over IP) |
| RS-485 Port | Serial bus for connecting multiple SIO boards |
| Baud Rate | Communication speed (must match connected devices) |
| Device Type | Baud Rate | Notes |
|---|---|---|
| Mercury SIO | 38400 | Default for most Mercury devices |
| Allegion Devices | 9600 | Schlage/Allegion readers and locks |
| OSDP Readers | 9600 or 38400 | Depends on reader configuration |
| Legacy Devices | 9600 | Older equipment may require lower speed |
Important: If using Allegion or Schlage devices, you must set the baud rate to 9600.
Before setting active ports, ensure you have:
For controllers with on-board reader connections (like EP1501), activate the internal port.
using Feenics.Keep.WebApi.Wrapper;
using Feenics.Keep.WebApi.Model;
// Get the controller
var controller = (await client.GetControllersAsync(currentInstance))
.OfType<MercuryControllerInfo>()
.First();
// Get available communication ports
var ports = await client.GetCommunicationPortDefinitionsAsync(controller);
// Find and display available ports
Console.WriteLine($"Available ports on {controller.CommonName}:");
foreach (var p in ports)
{
Console.WriteLine($" Driver {p.DriverNumber}: {p.CommonName}");
Console.WriteLine($" Internal: {p.IsInternal}");
Console.WriteLine($" Network: {p.IsNetworkPort}");
}
// Find the internal port
var internalPort = ports.Single(p => p.IsInternal);
// Set it as active
await client.SetActivePortAsync(controller, new ActivePortItem
{
DriverNumber = internalPort.DriverNumber
});
Console.WriteLine($"Set internal port (Driver {internalPort.DriverNumber}) as active");
For controllers with external SIO boards connected via RS-485.
// Find the RS-485 port (typically not internal and not network)
var rs485Port = ports.FirstOrDefault(p => !p.IsInternal && !p.IsNetworkPort);
if (rs485Port != null)
{
await client.SetActivePortAsync(controller, new ActivePortItem
{
DriverNumber = rs485Port.DriverNumber,
BaudRate = 38400 // Standard Mercury baud rate
});
Console.WriteLine($"Set RS-485 port (Driver {rs485Port.DriverNumber}) as active at 38400 baud");
}
// Allegion devices require 9600 baud rate
var allegionPort = ports.First(p => !p.IsInternal);
await client.SetActivePortAsync(controller, new ActivePortItem
{
DriverNumber = allegionPort.DriverNumber,
BaudRate = 9600 // Required for Allegion/Schlage devices
});
Console.WriteLine($"Configured port for Allegion devices at 9600 baud");
/// <summary>
/// Configures the appropriate active port based on controller type and devices
/// </summary>
public async Task ConfigureActivePortAsync(
MercuryControllerInfo controller,
bool useInternalPort = true,
int? baudRate = null)
{
var ports = await client.GetCommunicationPortDefinitionsAsync(controller);
CommunicationPortDefinitionItem selectedPort;
if (useInternalPort)
{
selectedPort = ports.SingleOrDefault(p => p.IsInternal);
if (selectedPort == null)
{
Console.WriteLine("No internal port available, using first available port");
selectedPort = ports.First();
}
}
else
{
selectedPort = ports.FirstOrDefault(p => !p.IsInternal && !p.IsNetworkPort)
?? ports.First();
}
var activePortConfig = new ActivePortItem
{
DriverNumber = selectedPort.DriverNumber
};
// Set baud rate if specified (required for non-internal ports)
if (baudRate.HasValue)
{
activePortConfig.BaudRate = baudRate.Value;
}
else if (!selectedPort.IsInternal)
{
// Default to 38400 for RS-485 ports
activePortConfig.BaudRate = 38400;
}
await client.SetActivePortAsync(controller, activePortConfig);
Console.WriteLine($"Active port configured:");
Console.WriteLine($" Port: {selectedPort.CommonName}");
Console.WriteLine($" Driver Number: {selectedPort.DriverNumber}");
if (activePortConfig.BaudRate > 0)
{
Console.WriteLine($" Baud Rate: {activePortConfig.BaudRate}");
}
}
// Get the current active port configuration
var activePorts = await client.GetActivePortsAsync(controller);
Console.WriteLine($"Active ports on {controller.CommonName}:");
foreach (var ap in activePorts)
{
Console.WriteLine($" Driver {ap.DriverNumber}: Baud Rate {ap.BaudRate}");
}
ACCESS_TOKEN="your-access-token"
INSTANCE_KEY="your-instance-key"
CONTROLLER_KEY="your-controller-key"
curl -X PUT \
"https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/activeports" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.ActivePortItem, Feenics.Keep.WebApi.Model",
"DriverNumber": 0,
"BaudRate": 38400
}'
curl -X PUT \
"https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/activeports" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.ActivePortItem, Feenics.Keep.WebApi.Model",
"DriverNumber": 1,
"BaudRate": 9600
}'
curl -X GET \
"https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/ports" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
curl -X GET \
"https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/activeports" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
| Property | Type | Description |
|---|---|---|
DriverNumber |
int |
Unique port identifier on the controller |
CommonName |
string |
Descriptive name for the port |
IsInternal |
bool |
True if port is built-in (on-board) |
IsNetworkPort |
bool |
True if port uses IP communication |
BaudRate |
int |
Communication speed (bits per second) |
| Practice | Description |
|---|---|
| Set port before adding downstreams | Active port must be configured first |
| Match baud rates | Controller and SIO must use same baud rate |
| Document port usage | Record which port connects to which devices |
| Use internal port when available | Simpler configuration for on-board connections |
| Test connectivity after configuration | Verify SIOs come online after port activation |
| Issue | Possible Cause | Solution |
|---|---|---|
| Downstream offline | Wrong driver number | Verify correct port is activated |
| No communication | Baud rate mismatch | Match baud rate to SIO settings |
| Intermittent connectivity | Wrong baud rate | Try 38400 or 9600 depending on devices |
| SIO not responding | Port not set as active | Call SetActivePortAsync before adding downstream |
| Multiple ports needed | Complex topology | Can activate multiple ports on same controller |
| Allegion device issues | Wrong baud rate | Must use 9600 for Allegion/Schlage |