Set Active Port on a Controller

Overview

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.

Key Concepts

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)

Common Baud Rate Settings

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.


Prerequisites

Before setting active ports, ensure you have:

  • ✅ A controller configured in the system
  • ✅ Knowledge of physical port wiring
  • ✅ Baud rate settings that match connected devices

C# Examples

Set Internal Port as Active

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");

Set RS-485 Port for External SIOs

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");
}

Set Port for Allegion/Schlage Devices

// 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");

Complete Controller Port Setup Function

/// <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 Current Active Ports

// 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}");
}

cURL Examples

Set Active Port

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
  }'

Set Port with 9600 Baud for Allegion

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
  }'

Get Communication Port Definitions

curl -X GET \
  "https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/ports" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

Get Active Ports

curl -X GET \
  "https://api.us.acresecurity.cloud/api/f/${INSTANCE_KEY}/controllers/${CONTROLLER_KEY}/activeports" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

Port Properties Reference

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)

Best Practices

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

Troubleshooting

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