An industrial OSDP (Open Supervised Device Protocol) gateway that bridges card readers with existing access control systems through a flexible plugin architecture.
Unlike traditional access controllers that limit third-party code execution, ApBox is designed as a pass-through gateway that preserves existing access control investments while enabling custom workflows and new technologies. Rather than making access decisions itself, ApBox typically forwards processed card data to existing access control systems, allowing organizations to enhance their current infrastructure without replacement.
- Elevator Dispatch Integration: Connect any OSDP reader to elevator dispatch systems by receiving card reads and calling elevator APIs
- Multi-Factor Authentication: Add facial recognition, biometric validation, or other security layers before forwarding credentials to access panels
- Custom Enrollment Workflows: Create specialized enrollment readers with validation logic tailored to organizational requirements
- Multi-System Lookup: Enable parking gate readers to query multiple databases and systems for comprehensive card validation
- New Credential Technologies: Integrate emerging credential formats not yet supported by legacy access controllers
APBox fills the gap between modern OSDP readers and existing access infrastructure, providing the flexibility to adopt new technologies and implement custom business logic without disrupting established access control investments.
- OSDP Protocol Support: Native support for OSDP card readers and communication
- Plugin Architecture: Extensible system for custom card processing logic
- Centralized Feedback Configuration: Unified system for managing success/failure feedback
- Web Management Interface: Modern Blazor Server UI with Blazorise components
- Real-time Dashboard: Live monitoring of reader status and card events
- Default Feedback Patterns: Pre-configured LED, beep, and display responses
- Idle State Management: Configurable permanent and heartbeat LED patterns
- System Configuration: Export/import system configuration and restart management
- Real-time Log Viewer: Live streaming logs with filtering and search capabilities
- Docker Deployment: Containerized deployment for easy scaling
- .NET 8: Core runtime and framework
- Blazor Server: Web interface with real-time updates
- Blazorise: Bootstrap-based UI component library
- MVVM Toolkit: Clean separation of UI and business logic
- SQLite: Lightweight database for configuration and logging
- NUnit: Test-driven development with comprehensive test coverage
- bUnit: Blazor component testing framework
graph TB
%% Reader Connections
Reader1[OSDP Reader 1] --> |OSDP| APBox[APBox Controller]
Reader2[OSDP Reader 2] --> |OSDP| APBox
Reader3[OSDP Reader 3] --> |OSDP| APBox
%% Plugin Architecture
APBox --> |Plugin Interface| PluginMgr[Plugin Manager]
PluginMgr --> Plugin1[Access Control Plugin]
PluginMgr --> Plugin2[Web Services Plugin]
PluginMgr --> Plugin3[IoT Hub Plugin]
PluginMgr --> Plugin4[Custom Plugin]
%% System Integrations via Plugins
Plugin1 --> |OSDP| AccessPanel[Access Control Panel]
Plugin2 --> |REST API| WebService[Web Services]
Plugin3 --> |MQTT| IoTHub[IoT Hub/Cloud Platform]
Plugin4 --> |Custom Protocol| External[External System]
%% External Systems
AccessPanel --> |Integration| PACS[Physical Access Control System]
WebService --> |API| Elevator[Elevator Dispatch System]
IoTHub --> |Analytics| Dashboard[Analytics Dashboard]
%% Data Flow
APBox --> |Event Logging| Logger[Event Logger]
%% Status Monitoring
APBox --> |Status| Monitor[Health Monitoring]
Monitor --> |Alerts| Notification[Notification System]
%% Styling
classDef readerClass fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef apboxClass fill:#f3e5f5,stroke:#4a148c,stroke-width:3px
classDef pluginClass fill:#fff8e1,stroke:#f57f17,stroke-width:2px
classDef systemClass fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
classDef infrastructureClass fill:#fff3e0,stroke:#e65100,stroke-width:2px
class Reader1,Reader2,Reader3 readerClass
class APBox apboxClass
class PluginMgr,Plugin1,Plugin2,Plugin3,Plugin4 pluginClass
class AccessPanel,WebService,IoTHub,PACS,Elevator,Dashboard,External systemClass
class Logger,Monitor,Notification infrastructureClass
- ApBox.Core: Main application hosting OSDP integration and plugin infrastructure
- ApBox.Web: Blazor Server management interface with MVVM pattern
- ApBox.Plugins: Plugin interfaces and reference implementations
public interface IApBoxPlugin
{
string Name { get; }
string Version { get; }
string Description { get; }
Task<bool> ProcessCardReadAsync(CardReadEvent cardRead);
Task InitializeAsync();
Task ShutdownAsync();
}
APBox provides a centralized feedback configuration system:
- Success Feedback: Configurable LED color, duration, beep count, and display message
- Failure Feedback: Separate configuration for failed card reads
- Idle State: Permanent LED and heartbeat flash patterns for inactive readers
- Real-time Configuration: Web-based configuration with live preview and auto-save
APBox includes a comprehensive web management interface with the following sections:
- Real-time metrics: Live card read statistics and system status
- Reader monitoring: Current status and configuration of all readers
- Recent events: Latest card read events with success/failure indicators
- Plugin status: Information about loaded plugins and their versions
- Readers: Add, edit, and manage OSDP reader configurations
- Feedback: Configure success/failure LED patterns, beeps, and display messages
- System: Export/import system configuration, restart management, and log viewer
- Card Simulation: Test card reads without physical hardware
- Batch Testing: Generate multiple test events for system validation
- Continuous Simulation: Ongoing random card reads for stress testing
β οΈ Early Development Notice
This project is in early development. After pulling code from Git, you must delete the SQLite database file (apbox.db
) as there are currently no migration scripts. The database will be recreated automatically on the next run.
- .NET 8 SDK
- Docker (optional, for containerized deployment)
-
Clone the repository
git clone https://github.com/Z-bit-Systems-LLC/APBox.git cd ApBox
-
Restore dependencies
dotnet restore
-
Build the solution
dotnet build
-
Run tests
dotnet test
-
Start the web application
dotnet run --project src/ApBox.Web
-
Access the web interface
Open your browser and navigate to
http://localhost:5271
ApBox follows Test-Driven Development (TDD) practices:
# Watch mode for TDD workflow
dotnet watch test --project tests/ApBox.Core.Tests
# Run tests with detailed output
dotnet test -v normal
# Run only unit tests
dotnet test --filter "Category=Unit"
# Generate coverage report
dotnet-coverage collect "dotnet test" -f xml -o coverage.xml
ApBox can be built as a self-contained single executable file that includes all .NET libraries, eliminating the need to install .NET runtime on target systems.
Build a single executable with all dependencies included:
# Windows x64
dotnet publish src/ApBox.Web -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -o publish/win-x64
# Linux x64
dotnet publish src/ApBox.Web -c Release -r linux-x64 --self-contained -p:PublishSingleFile=true -o publish/linux-x64
# Linux ARM64 (for Raspberry Pi)
dotnet publish src/ApBox.Web -c Release -r linux-arm64 --self-contained -p:PublishSingleFile=true -o publish/linux-arm64
For smaller file sizes and better performance:
# Trimmed build (removes unused code)
dotnet publish src/ApBox.Web -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=true -o publish/win-x64-trimmed
# Ready-to-run (faster startup)
dotnet publish src/ApBox.Web -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:PublishReadyToRun=true -o publish/win-x64-r2r
The single-file executable does not automatically include plugin DLLs since they are loaded dynamically at runtime. You have two options:
# Build and publish main application
dotnet publish src/ApBox.Web -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -o publish/win-x64
# Build plugins separately
dotnet build src/ApBox.SamplePlugins -c Release -o publish/win-x64/plugins
# Deploy both executable and plugins folder
copy publish/win-x64/ApBox.Web.exe C:\ApBox\
xcopy publish/win-x64/plugins C:\ApBox\plugins\ /E /I
Add plugin projects as dependencies to force inclusion:
<!-- Add to src/ApBox.Web/ApBox.Web.csproj -->
<ItemGroup>
<ProjectReference Include="../ApBox.SamplePlugins/ApBox.SamplePlugins.csproj" />
</ItemGroup>
Then publish normally - plugins will be embedded in the executable.
The published executable includes:
- All .NET runtime components
- Application code and dependencies
- SQLite database provider
- Web assets and static files
- Plugin DLLs (only if using Option 2 above)
Deployment examples:
# Windows (with separate plugins)
copy publish/win-x64/ApBox.Web.exe C:\ApBox\
xcopy publish/win-x64/plugins C:\ApBox\plugins\ /E /I
C:\ApBox\ApBox.Web.exe
# Linux (with separate plugins)
cp publish/linux-x64/ApBox.Web /opt/apbox/
cp -r publish/linux-x64/plugins /opt/apbox/
/opt/apbox/ApBox.Web
Common runtime identifiers for APBox deployment:
Platform | RID | Use Case |
---|---|---|
win-x64 |
Windows 64-bit | Development, Windows servers |
win-arm64 |
Windows ARM64 | Windows on ARM devices |
linux-x64 |
Linux 64-bit | Ubuntu, Debian, CentOS |
linux-arm |
Linux ARM32 | Raspberry Pi 3/4 (32-bit) |
linux-arm64 |
Linux ARM64 | Raspberry Pi 4 (64-bit), Strato Pi |
Option | Description | Impact |
---|---|---|
--self-contained |
Includes .NET runtime | Larger size, no runtime dependency |
-p:PublishSingleFile=true |
Bundles everything into one file | Single executable |
-p:PublishTrimmed=true |
Removes unused assemblies | Smaller size, faster startup |
-p:PublishReadyToRun=true |
Pre-compiles to native code | Faster startup, larger size |
ApBox supports exporting and importing complete system configurations through the web interface or API. The configuration export includes all readers, feedback settings, and system information.
The complete configuration export follows this JSON schema:
{
"exportVersion": "1.0",
"exportedAt": "2024-01-01T12:00:00.000Z",
"systemInfo": {
"apBoxVersion": "1.0.0.0",
"framework": ".NET 8.0.0",
"platform": "Win32NT (Microsoft Windows 10.0.22631)",
"machineName": "PRODUCTION-SERVER",
"osVersion": "Microsoft Windows NT 10.0.22631.0",
"processorCount": 8,
"workingDirectory": "C:\\ApBox",
"startTime": "2024-01-01T12:00:00.000Z"
},
"readers": [
{
"readerId": "12345678-1234-1234-1234-123456789abc",
"readerName": "Main Entrance",
"address": 1,
"isEnabled": true,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"serialPort": "COM1",
"baudRate": 9600,
"securityMode": "ClearText",
"secureChannelKey": null,
"pluginMappings": [
{
"pluginId": "AccessControlPlugin",
"executionOrder": 1,
"isEnabled": true
},
{
"pluginId": "TimeBasedAccessPlugin",
"executionOrder": 2,
"isEnabled": true
},
{
"pluginId": "AuditLoggingPlugin",
"executionOrder": 3,
"isEnabled": false
}
]
}
],
"feedbackConfiguration": {
"successFeedback": {
"type": "Success",
"beepCount": 1,
"ledColor": "Green",
"ledDuration": 1000,
"displayMessage": "ACCESS GRANTED"
},
"failureFeedback": {
"type": "Failure",
"beepCount": 3,
"ledColor": "Red",
"ledDuration": 2000,
"displayMessage": "ACCESS DENIED"
},
"idleState": {
"permanentLedColor": "Blue",
"heartbeatFlashColor": "Green"
}
}
}
Property | Type | Description |
---|---|---|
readerId |
string (GUID) |
Unique identifier for the reader |
readerName |
string |
Human-readable name (max 100 chars) |
address |
number (byte) |
OSDP bus address (1-127) |
isEnabled |
boolean |
Whether reader is active |
serialPort |
string |
Serial port (e.g., "COM1", "/dev/ttyUSB0") |
baudRate |
number |
Communication speed (default: 9600) |
securityMode |
string |
OSDP security: "ClearText", "Install", "Secure" |
secureChannelKey |
byte[] |
Encryption key for secure mode |
pluginMappings |
array |
List of plugins assigned to this reader |
Property | Type | Description |
---|---|---|
pluginId |
string |
Unique identifier of the plugin |
executionOrder |
number |
Plugin execution sequence (1-based) |
isEnabled |
boolean |
Whether plugin is active for this reader |
Property | Type | Description |
---|---|---|
type |
string |
"None", "Success", "Failure", "Custom" |
beepCount |
number |
Number of beeps (0+ for success/failure) |
ledColor |
string |
"Off", "Red", "Green", "Amber", "Blue" |
ledDuration |
number |
LED duration in milliseconds |
displayMessage |
string |
Text shown on reader display |
The system validates imported configurations for:
- JSON Format: Valid JSON structure and required fields
- Version Compatibility: Warns about version mismatches
- Reader Validation: No duplicate names or addresses, valid names
- Plugin Mappings: Valid plugin IDs, unique execution orders per reader
- Feedback Validation: Positive durations, non-negative beep counts
- Data Integrity: Proper GUIDs, valid enums, range checking
Web Interface:
- Navigate to Configuration β System
- Click "Export Configuration" to download JSON file
- Click "Import Configuration" to upload and validate JSON file
- Review validation results before confirming import
File Operations:
- Export creates timestamped backup with system information and plugin assignments
- Import overwrites existing configurations (readers and plugin mappings are updated if they exist)
- Plugin assignments are preserved and validated during import
- Validation prevents importing invalid or conflicting data
- System restart may be required after major configuration changes
public class CardReadEvent
{
public Guid ReaderId { get; set; }
public string CardNumber { get; set; }
public int BitLength { get; set; }
public DateTime Timestamp { get; set; }
public string ReaderName { get; set; }
public Dictionary<string, object> AdditionalData { get; set; }
}
# Build Docker image
docker build -t apbox:latest .
# Run container
docker run -d -p 8080:80 --name apbox apbox:latest
- Development: Raspberry Pi 4 or compatible
- Production: Strato Pi CM Duo v3 (industrial-grade)
Raspberry Pi Configuration (Raspbian)
When deploying on Raspberry Pi 4 with Raspbian, the application requires proper permissions to access serial ports for OSDP communication. Without these permissions, ApBox will run but produce no OSDP output.
Solution 1: Add User to dialout Group (Recommended)
# Add current user to dialout group
sudo usermod -a -G dialout $USER
# Verify group membership
groups $USER
# Log out and back in for changes to take effect
Solution 2: Run with sudo (Not Recommended for Production)
# Run with elevated privileges
sudo dotnet run --project src/ApBox.Web
# or for single executable:
sudo ./ApBox.Web
Note: The dialout group approach is preferred for production deployments as it follows the principle of least privilege and doesn't require running the entire application as root.
APBox includes built-in systemd support for running as a Linux service. This provides automatic startup, process monitoring, and clean shutdown handling.
-
Build the application for Linux:
# Self-contained build for Linux x64 dotnet publish src/ApBox.Web -c Release -r linux-x64 --self-contained -p:PublishSingleFile=true -o publish/linux-x64 # Or for Raspberry Pi (ARM64) dotnet publish src/ApBox.Web -c Release -r linux-arm64 --self-contained -p:PublishSingleFile=true -o publish/linux-arm64
-
Set up dialout permissions (see Linux Deployment Requirements above):
sudo usermod -a -G dialout apbox
-
Create service user:
# Create dedicated service user sudo useradd -r -s /bin/false apbox sudo usermod -a -G dialout apbox
-
Deploy the application:
# Create application directory sudo mkdir -p /opt/apbox sudo chown apbox:apbox /opt/apbox # Copy application files sudo cp publish/linux-x64/ApBox.Web /opt/apbox/ sudo chmod +x /opt/apbox/ApBox.Web # Copy plugins if using separate plugin deployment sudo cp -r publish/linux-x64/plugins /opt/apbox/ 2>/dev/null || true sudo chown -R apbox:apbox /opt/apbox
-
Create systemd service file:
sudo tee /etc/systemd/system/apbox.service > /dev/null << 'EOF' [Unit] Description=APBox OSDP Gateway Service Documentation=https://github.com/Z-bit-Systems-LLC/ApBox After=network.target Wants=network.target [Service] Type=notify User=apbox Group=apbox WorkingDirectory=/opt/apbox ExecStart=/opt/apbox/ApBox.Web Restart=always RestartSec=5 SyslogIdentifier=apbox Environment=ASPNETCORE_ENVIRONMENT=Production Environment=ASPNETCORE_URLS=http://0.0.0.0:5000 # Security settings NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ProtectHome=yes ReadWritePaths=/opt/apbox # Resource limits MemoryMax=512M TasksMax=100 [Install] WantedBy=multi-user.target EOF
-
Enable and start the service:
# Reload systemd configuration sudo systemctl daemon-reload # Enable service to start at boot sudo systemctl enable apbox # Start the service sudo systemctl start apbox # Check service status sudo systemctl status apbox
# Start the service
sudo systemctl start apbox
# Stop the service
sudo systemctl stop apbox
# Restart the service
sudo systemctl restart apbox
# Check service status
sudo systemctl status apbox
# View service logs
sudo journalctl -u apbox -f
# View logs since last boot
sudo journalctl -u apbox -b
# View logs for specific time period
sudo journalctl -u apbox --since "1 hour ago"
# Disable service from starting at boot
sudo systemctl disable apbox
# Enable service to start at boot
sudo systemctl enable apbox
The service stores its data in the working directory (/opt/apbox
):
- Database:
apbox.db
(SQLite database file) - Logs: Application logs are sent to systemd journal
- Plugins: Plugin DLLs are loaded from
plugins/
subdirectory - Configuration: System configuration can be exported/imported via web interface
Once the service is running, access the web interface at:
- HTTP:
http://[server-ip]:5000
- Local access:
http://localhost:5000
Service fails to start:
# Check detailed service status
sudo systemctl status apbox -l
# View recent error logs
sudo journalctl -u apbox -n 50
# Check if port is already in use
sudo netstat -tulpn | grep :5000
Permission issues:
# Verify user is in dialout group
groups apbox
# Check file permissions
ls -la /opt/apbox/
# Fix permissions if needed
sudo chown -R apbox:apbox /opt/apbox
sudo chmod +x /opt/apbox/ApBox.Web
OSDP communication problems:
# List available serial ports
ls -la /dev/tty*
# Check port permissions
ls -la /dev/ttyUSB0 # or your specific port
# Test serial port access as apbox user
sudo -u apbox cat /dev/ttyUSB0
The systemd integration provides:
- Type=notify: Service notifies systemd when fully initialized
- Automatic restart: Service restarts automatically if it crashes
- Resource limits: Memory and task limits prevent resource exhaustion
- Security: Runs with minimal privileges and restricted filesystem access
- Logging: All logs are captured by systemd journal
- Clean shutdown: Proper shutdown handling for database and OSDP connections
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Write tests for your changes
- Implement your feature following TDD practices
- Ensure all tests pass (
dotnet test
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
APBox maintains comprehensive test coverage:
- Unit Tests: Core business logic and plugin interfaces
- Integration Tests: OSDP communication and database operations
- Component Tests: Blazor UI components with bUnit
- End-to-End Tests: Complete workflow validation
This project is licensed under the Eclipse Public License v2.0 - see the LICENSE file for details.
- Documentation: Wiki
- Issues: GitHub Issues
APBox includes 4 comprehensive sample plugins that demonstrate the plugin architecture. Here's how to test them:
# Build the sample plugins
dotnet build src/ApBox.SamplePlugins
# Copy plugins to the web application plugins directory
mkdir -p src/ApBox.Web/plugins
cp src/ApBox.SamplePlugins/bin/Debug/net8.0/ApBox.SamplePlugins.dll src/ApBox.Web/plugins/
# Run the web application
dotnet run --project src/ApBox.Web
# The application will start on http://localhost:5271
Open your browser to http://localhost:5271
and you'll see:
- Dashboard: Real-time metrics showing active readers and loaded plugins
- Recent Card Events: Live table of card read events
- Reader Status: Current status of configured readers
Navigate to http://localhost:5271/test-card-reads
to use the card simulation interface:
- Select a reader from the dropdown
- Enter a card number or click "Generate Random"
- Choose bit length (26-bit or 37-bit)
- Click "Simulate Card Read"
- "Simulate 5 Random Reads": Quick batch of 5 random events
- "Simulate 10 Random Reads": Larger batch for stress testing
- "Start Continuous Simulation": Ongoing random events every 2-5 seconds
- "Stop Continuous": Stop the continuous simulation
The included sample plugins will process your card reads:
- Authorized cards:
12345678
,87654321
,11111111
,22222222
,12345123
,98765987
- Authorized: Green LED, 1 beep, "ACCESS GRANTED"
- Unauthorized: Red LED, 3 beeps, "ACCESS DENIED"
- Card
12345678
: Business hours only (Mon-Fri, 8 AM - 5 PM) - Card
87654321
: Extended hours (Mon-Sat, 6 AM - 10 PM) - Card
11111111
: 24/7 access - Card
22222222
: Weekends only (Sat-Sun, 7 AM - 3 PM) - Time allowed: Green LED, 2 beeps, "TIME ACCESS OK"
- Time restricted: Amber LED, 2 beeps, "TIME RESTRICTED"
- Records all events to
logs/audit/audit-YYYY-MM-DD.jsonl
- Provides brief blue LED flash (100ms)
- Check the logs directory for JSON audit entries
- Logs all events to the standard .NET logging system
- Tracks statistics (total, successful, failed events)
- No visual feedback (passive monitoring)
- Check console output for log entries
With the simulation running:
- Open multiple browser tabs to
http://localhost:5271
- Start continuous simulation in the test page
- Watch the dashboard update in real-time:
- Recent Card Events table shows new entries instantly
- Total Events counter increments
- No page refresh needed - SignalR provides live updates
Monitor the application logs to see plugin activity:
# The console will show detailed plugin processing:
# - Access Control Plugin processing card 12345678
# - Time-Based Access Plugin checking schedule
# - Audit entries being written
# - Event statistics being tracked
Try these test scenarios:
- Use card
12345678
during business hours - Should get green LED from both Access Control and Time-Based plugins
- Use card
99999999
(not in authorized list) - Should get red LED from Access Control plugin
- Use card
12345678
outside business hours (evenings/weekends) - Should get amber LED from Time-Based plugin
- Use card
11111111
any time - Should always get green LED
Use the Test Card Reads page to develop and test your own plugins:
- Create your plugin following the samples in
src/ApBox.SamplePlugins/
- Build and deploy to the plugins directory
- Restart the application to load new plugins
- Test with various card numbers and scenarios
- Check the dashboard for real-time results
This testing environment lets you validate plugin behavior without physical card readers, making development fast and reliable.
- Core foundation and plugin system
- Simplified plugin interface with centralized feedback
- Real-time SignalR dashboard with live updates
- Comprehensive Blazor web interface with Blazorise components
- Sample plugins and testing infrastructure
- bUnit UI testing with comprehensive test coverage
- Centralized feedback configuration system
- System configuration export/import functionality
- Real-time log viewer with filtering
- System restart management
- OSDP integration and communication
- Docker deployment support
- Advanced plugin marketplace
- Enhanced security features
- Production hardware optimization
- Cloud integration capabilities
- Advanced analytics and reporting