Controllers are the heart of your access control system—they manage readers, process card reads, and make access decisions. This guide shows you how to add and configure Mercury controllers.
A controller is an intelligent device that:
| Controller | Max Readers | Max Inputs | Max Outputs |
|---|---|---|---|
| EP1501 | 2 | 8 | 4 |
| EP1502 | 4 | 16 | 8 |
| EP2500 | 64 | 256 | 128 |
| EP4502 | 4 | 8 | 4 |
| LP1501 | 2 | 8 | 4 |
| LP1502 | 4 | 16 | 8 |
| LP2500 | 64 | 256 | 128 |
| LP4502 | 4 | 8 | 4 |
| MP1501 | 2 | 8 | 4 |
| MP1502 | 4 | 16 | 8 |
| MP2500 | 64 | 256 | 128 |
| MP4502 | 4 | 8 | 4 |
📝 Note: The same process applies to all controller types—just use the appropriate
*Infoclass (e.g.,Ep1502Info,Lp2500Info,Mp1501Info,Ep4502Info). 💡 4502 Extended Features: The 4502 models support High Assurance Credential Authentication, BACnet IP protocol, elevator destination dispatch, and power management analytics.
EPs only support outdated and insecure TLS 1.1. Please consider upgrading to MPs for TLS 1.3, if security or encryption is a concern.
For reliable connectivity, try disabling TLS on EPs.
Before adding a controller:
var controller = await client.AddControllerAsync(currentInstance, new Ep1501Info
{
CommonName = "Main Entrance Controller",
MacAddress = "00:1A:2B:3C:4D:5E", // From controller label
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2" // Eastern Time with DST
});
Console.WriteLine($"Controller added: {controller.CommonName}");
Console.WriteLine($"Key: {controller.Key}");
Console.WriteLine($"Online: {controller.Status?.IsOnline}");
curl -X POST \
https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/controllers \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"$type": "Feenics.Keep.WebApi.Model.Ep1501Info, Feenics.Keep.WebApi.Model",
"CommonName": "Main Entrance Controller",
"MacAddress": "00:1A:2B:3C:4D:5E",
"TimeZone": "EST5EDT,M3.2.0/2,M11.1.0/2"
}'
// EP1501 - Standard single door
var ep1501 = await client.AddControllerAsync(currentInstance, new Ep1501Info
{
CommonName = "Office Door",
MacAddress = "00:1A:2B:3C:4D:5E",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// LP1501 - LP single door
var lp1501 = await client.AddControllerAsync(currentInstance, new Lp1501Info
{
CommonName = "Conference Room",
MacAddress = "00:1A:2B:3C:4D:5F",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// MP1501 - MP single door
var mp1501 = await client.AddControllerAsync(currentInstance, new Mp1501Info
{
CommonName = "Storage Room",
MacAddress = "00:1A:2B:3C:4D:70",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// EP1502 - Standard two door
var ep1502 = await client.AddControllerAsync(currentInstance, new Ep1502Info
{
CommonName = "Building Lobby",
MacAddress = "00:1A:2B:3C:4D:60",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// LP1502 - LP two door
var lp1502 = await client.AddControllerAsync(currentInstance, new Lp1502Info
{
CommonName = "Parking Garage",
MacAddress = "00:1A:2B:3C:4D:71",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// MP1502 - MP two door
var mp1502 = await client.AddControllerAsync(currentInstance, new Mp1502Info
{
CommonName = "Warehouse Entrance",
MacAddress = "00:1A:2B:3C:4D:72",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
The TimeZone property uses POSIX timezone format for daylight saving time support.
| Region | TimeZone String |
|---|---|
| Eastern (US) | EST5EDT,M3.2.0/2,M11.1.0/2 |
| Central (US) | CST6CDT,M3.2.0/2,M11.1.0/2 |
| Mountain (US) | MST7MDT,M3.2.0/2,M11.1.0/2 |
| Pacific (US) | PST8PDT,M3.2.0/2,M11.1.0/2 |
| Arizona (no DST) | MST7 |
| UK/London | GMT0BST,M3.5.0/1,M10.5.0 |
| Central Europe | CET-1CEST,M3.5.0,M10.5.0/3 |
EST5EDT,M3.2.0/2,M11.1.0/2
│ │ │ │
│ │ │ └── End DST: November, 1st week, Sunday at 2:00
│ │ └── Start DST: March, 2nd week, Sunday at 2:00
│ └── DST name
└── Standard name and offset (5 hours behind UTC)
For 64-bit card numbers (some HID formats), enable large encoded card support (on the Controller and the CardFormat):
var controller = await client.AddControllerAsync(currentInstance, new Ep2500Info
{
CommonName = "Secure Entry",
MacAddress = "00:1A:2B:3C:4D:62",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2",
EnableLargeEncodedCardNumber = true
});
If a controller is already registered but you need to find it:
var controller = await client.GetControllerByMacAddressAsync(currentInstance, "00:1A:2B:3C:4D:5E");
if (controller != null)
{
Console.WriteLine($"Found controller: {controller.CommonName}");
Console.WriteLine($"Online: {controller.Status?.IsOnline}");
}
else
{
Console.WriteLine("Controller not found");
}
After adding, verify the controller is online:
var controller = (await client.SearchAsync(currentInstance, $"{{\\"_t\\":\\"Controller\\",\\"_id\\":\\"{controllerKey}\\"}}"))
.OfType<ControllerInfo>().FirstOrDefault();
Console.WriteLine($"Controller: {controller.CommonName}");
Console.WriteLine($"Online: {controller.Status?.IsOnline}");
Console.WriteLine($"Firmware: {controller.Version}");
Console.WriteLine($"Last Updated: {controller.LastUpdatedOn}");
if (controller.Status?.IsOnline == true)
{
Console.WriteLine("✅ Controller is connected and operational");
}
else
{
Console.WriteLine("⚠️ Controller is offline - check network connectivity");
}
Set which ports are active for reader connections:
// Enable ports 1 and 2 on a two-door controller
controller.ActivePorts = new[]
{
new ActivePortItem { DriverNumber = 1 },
new ActivePortItem { DriverNumber = 2 }
};
await client.UpdateControllerAsync(controller);
After adding a controller, you typically add downstreams, readers, and link to access levels:
// Step 1: Add the controller
var controller = await client.AddControllerAsync(currentInstance, new Ep1502Info
{
CommonName = "Building A - Main",
MacAddress = "00:1A:2B:3C:4D:63",
TimeZone = "EST5EDT,M3.2.0/2,M11.1.0/2"
});
// Step 2: Add a downstream (MR50 dual reader interface)
var downstream = await client.AddDownstreamAsync(controller, new Mr50Info
{
CommonName = "Front Door Module",
Address = 1
});
// Step 3: Add readers as peripherals to the downstream
var entryReader = await client.AddPeripheralToDownStreamAsync(downstream, new MercuryReaderInfo
{
CommonName = "Front Door - Entry",
Address = 1,
MercuryReaderType = MercuryReaderTypes.Wiegand,
MercuryReaderAccessMethod = MercuryReaderAccessMethods.Card
});
var exitReader = await client.AddPeripheralToDownStreamAsync(downstream, new MercuryReaderInfo
{
CommonName = "Front Door - Exit",
Address = 2,
MercuryReaderType = MercuryReaderTypes.Wiegand,
MercuryReaderAccessMethod = MercuryReaderAccessMethods.Card
});
Console.WriteLine("Setup complete!");
| Practice | Recommendation |
|---|---|
| Naming Convention | Use location-based names: “Building A - Lobby” |
| MAC Address Format | Use colons: 00:1A:2B:3C:4D:5E |
| Time Zone | Set accurately for correct schedule enforcement |
| Firmware | Keep firmware updated for security and features |
| Verify Status | Check controller comes online after adding |
| Issue | Cause | Solution |
|---|---|---|
| Controller offline after adding | Network misconfiguration | Verify IP, DNS, and firewall rules |
DuplicateMacAddress error |
MAC already registered | Find existing controller or verify MAC |
| Wrong time zone | Incorrect POSIX string | Use reference table above |