Hybrid Office Locker System for Employees Who Hot Desk
When employees hot desk, they need secure storage for personal belongings, equipment, and valuables throughout the workday. A well-designed locker system integrates with existing badge access, provides real-time availability tracking, and offers programmatic control for custom workplace workflows. This guide covers the technical implementation of a hybrid office locker system built for hot-desking environments.
Why Hot-Desking Requires Smart Locker Systems
Traditional lockers with combination locks or physical keys don’t work in hot-desking scenarios. Employees can’t remember codes, keys get lost, and there’s no way to track which lockers are available or who currently has which locker assigned. Smart locker systems solve these problems by providing badge-controlled access, automatic assignment, and integration with desk booking platforms.
Modern locker systems connect to your identity provider, automatically assigning lockers when employees book desks and releasing them when reservations end. This automation removes friction from the hot-desking experience while providing security teams with audit logs of every access event.
Core Locker System Architecture
A smart locker system consists of four primary components: the locker controller hardware, the backend API service, the integration layer, and the user-facing applications. Understanding how these components interact helps you design a system that scales across multiple office locations.
Locker Controller Hardware
The controller hardware manages individual locker doors and communicates with the central system. Most commercial smart locker solutions use one of three architectures:
Networked Controllers: Each locker has a network-connected controller that communicates over Ethernet or WiFi. These controllers accept commands from a central server and report status changes. Examples include systems from Essential Robotics and OpenSpaces.
Bus-Based Systems: Lockers connect to a central controller via a communication bus (RS-485 or CAN bus). This architecture reduces wiring complexity but requires longer cable runs. Bosch Smart Locker and Stanley Access Control use this approach.
Standalone Smart Locks: Individual battery-powered smart locks retrofit onto existing lockers. August Home and SmartRent offer locks that connect via Zigbee, Z-Wave, or WiFi. These work well for organizations wanting to upgrade existing furniture without full system replacement.
For new installations, networked controllers provide the most reliable performance and easiest integration. Here’s a typical controller specification:
# Locker controller specification
class LockerController:
def __init__(self, ip_address, locker_count):
self.ip_address = ip_address
self.locker_count = locker_count
self.status = [None] * locker_count # None=available, str=user_id=assigned
def get_status(self):
"""Poll controller for current locker states."""
# Returns list of dicts with locker_id, status, last_access, battery_level
pass
def open_locker(self, locker_id, user_id, duration_seconds=3600):
"""Unlock specific locker for timed access."""
pass
def assign_locker(self, locker_id, user_id, reservation_id):
"""Permanently assign locker for reservation duration."""
pass
Building the Locker API Service
The backend API handles all business logic: user authentication, locker assignment, access logging, and integration with other workplace systems. Here’s a Flask-based implementation of the core locker service:
from flask import Flask, request, jsonify
from datetime import datetime, timedelta
from functools import wraps
app = Flask(__name__)
# In-memory storage (replace with database in production)
lockers = {}
reservations = {}
access_logs = []
class Locker:
def __init__(self, locker_id, location, size='medium'):
self.id = locker_id
self.location = location # e.g., "floor-3-north"
self.size = size # small, medium, large
self.status = 'available'
self.current_user = None
self.current_reservation = None
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token or not token.startswith('Bearer '):
return jsonify({'error': 'Unauthorized'}), 401
# Verify token against identity provider
# In production, validate JWT or check against SSO
return f(*args, **kwargs)
return decorated
@app.route('/api/lockers', methods=['GET'])
@require_auth
def list_lockers():
"""List all lockers with availability status."""
location = request.args.get('location')
size = request.args.get('size')
available_lockers = [
{
'id': locker.id,
'location': locker.location,
'size': locker.size,
'status': locker.status
}
for locker in lockers.values()
if (not location or locker.location == location)
and (not size or locker.size == size)
]
return jsonify({'lockers': available_lockers})
@app.route('/api/lockers/assign', methods=['POST'])
@require_auth
def assign_locker():
"""Assign a locker to user for their desk booking."""
data = request.json
user_id = data.get('user_id')
desk_booking_id = data.get('desk_booking_id')
desired_location = data.get('preferred_location')
# Find available locker in preferred location
available = [
locker for locker in lockers.values()
if locker.status == 'available'
and (not desired_location or locker.location == desired_location)
]
if not available:
return jsonify({'error': 'No lockers available'}), 409
locker = available[0]
locker.status = 'assigned'
locker.current_user = user_id
locker.current_reservation = desk_booking_id
reservation = {
'id': desk_booking_id,
'locker_id': locker.id,
'user_id': user_id,
'assigned_at': datetime.utcnow().isoformat(),
'expires_at': (datetime.utcnow() + timedelta(hours=10)).isoformat()
}
reservations[desk_booking_id] = reservation
return jsonify({
'locker_id': locker.id,
'location': locker.location,
'reservation': reservation
})
@app.route('/api/lockers/<locker_id>/access', methods=['POST'])
@require_auth
def access_locker(locker_id):
"""Record locker access event and trigger hardware unlock."""
if locker_id not in lockers:
return jsonify({'error': 'Locker not found'}), 404
locker = lockers[locker_id]
user_id = request.json.get('user_id')
# Verify user has active reservation for this locker
active_reservation = None
for res in reservations.values():
if res['locker_id'] == locker_id and res['user_id'] == user_id:
active_reservation = res
break
if not active_reservation:
return jsonify({'error': 'No active reservation'}), 403
# Log access event
access_log = {
'timestamp': datetime.utcnow().isoformat(),
'locker_id': locker_id,
'user_id': user_id,
'action': 'unlock'
}
access_logs.append(access_log)
# Trigger hardware unlock (communicate with controller)
# controller.open_locker(locker_id, user_id)
return jsonify({'status': 'unlocked', 'log': access_log})
@app.route('/api/lockers/<locker_id>/release', methods=['POST'])
@require_auth
def release_locker(locker_id):
"""Release locker when desk booking ends."""
if locker_id not in lockers:
return jsonify({'error': 'Locker not found'}), 404
locker = lockers[locker_id]
if locker.status == 'available':
return jsonify({'error': 'Locker already released'}), 400
# Log release event
access_logs.append({
'timestamp': datetime.utcnow().isoformat(),
'locker_id': locker_id,
'user_id': locker.current_user,
'action': 'release'
})
# Clear reservation and make available
if locker.current_reservation in reservations:
del reservations[locker.current_reservation]
locker.status = 'available'
locker.current_user = None
locker.current_reservation = None
return jsonify({'status': 'released'})
Integrating with Desk Booking Systems
The locker system achieves its full potential when integrated with desk booking platforms. When an employee books a desk, the system automatically assigns an available locker nearby. When the booking ends, the locker automatically releases for the next employee.
Here’s how to integrate with a desk booking API:
import requests
from datetime import datetime
class DeskBookingIntegration:
def __init__(self, desk_api_url, locker_api_url, api_key):
self.desk_api = desk_api_url
self.locker_api = locker_api_url
self.api_key = api_key
self.headers = {'Authorization': f'Bearer {api_key}'}
def on_desk_booked(self, booking_event):
"""Handle desk booking creation event."""
user_id = booking_event['user_id']
booking_id = booking_event['booking_id']
floor = booking_event['floor']
# Find locker on same floor as booked desk
location = f'floor-{floor}'
# Request locker assignment
response = requests.post(
f'{self.locker_api}/lockers/assign',
json={
'user_id': user_id,
'desk_booking_id': booking_id,
'preferred_location': location
},
headers=self.headers
)
if response.status_code == 200:
locker = response.json()
print(f"Assigned locker {locker['locker_id']} to user {user_id}")
# Optionally notify user via email or Slack
return locker
else:
print(f"No lockers available for booking {booking_id}")
return None
def on_desk_released(self, booking_event):
"""Handle desk booking cancellation or end event."""
booking_id = booking_event['booking_id']
# Find associated locker
response = requests.get(
f'{self.locker_api}/reservations/{booking_id}',
headers=self.headers
)
if response.status_code == 200:
reservation = response.json()
locker_id = reservation['locker_id']
# Release the locker
requests.post(
f'{self.locker_api}/lockers/{locker_id}/release',
headers=self.headers
)
print(f"Released locker {locker_id} from booking {booking_id}")
Badge Access Integration
Most hybrid offices already have badge access systems. Integrating locker access with existing badges simplifies the user experience—no additional credentials needed. Here’s how to connect with common access control platforms:
class BadgeAccessIntegration:
def __init__(self, access_provider='honeywell'):
self.provider = access_provider
# Provider-specific configuration
self.api_endpoints = {
'honeywell': 'https://api.honeywell-buildings.com/v1',
'assa': 'https://api.assaabloy.com/v2',
'bosch': 'https://api.bosch-security.com/v1'
}
def sync_user_credentials(self, user_id, badge_id):
"""Sync user badge to locker system for access control."""
# This ensures the user's badge can open their assigned locker
# Implementation varies by locker hardware vendor
pass
def check_access_permission(self, user_id, locker_id):
"""Verify user has permission to access specific locker."""
# Query access control system for user permissions
# Return True if user has access, False otherwise
pass
def log_access_event(self, badge_id, locker_id, timestamp, action):
"""Send access event to central security system."""
event_data = {
'badge_id': badge_id,
'door_id': f'locker-{locker_id}',
'timestamp': timestamp,
'action': action
}
# Send to security logging system
pass
Locker Fleet Management
When managing hundreds of lockers across multiple floors and buildings, fleet management becomes critical. Here’s a dashboard-ready data structure for monitoring:
# Locker fleet status aggregation
def get_fleet_status(lockers):
"""Generate fleet-wide statistics for dashboard display."""
total = len(lockers)
available = sum(1 for l in lockers if l.status == 'available')
assigned = sum(1 for l in lockers if l.status == 'assigned')
maintenance = sum(1 for l in lockers if l.status == 'maintenance')
# Group by location
by_location = {}
for locker in lockers:
if locker.location not in by_location:
by_location[locker.location] = {'total': 0, 'available': 0}
by_location[locker.location]['total'] += 1
if locker.status == 'available':
by_location[locker.location]['available'] += 1
return {
'summary': {
'total': total,
'available': available,
'assigned': assigned,
'maintenance': maintenance,
'utilization_rate': (assigned / total * 100) if total > 0 else 0
},
'by_location': by_location,
'last_updated': datetime.utcnow().isoformat()
}
Deployment Considerations
When deploying smart lockers in hybrid offices, several practical factors affect success:
Power and Network: Networked lockers require both power and Ethernet connectivity to each controller. Plan cable routes during office construction. For retrofit installations, consider PoE (Power over Ethernet) to reduce electrical work. Battery-powered smart locks work for wireless scenarios but require regular battery replacement.
Location Strategy: Place lockers near high-traffic areas like elevator banks and stairwells. Consider zoning—lockers for each floor or department reduce congestion. Provide a mix of sizes: small for wallets and phones, medium for bags and laptops, large for coats and equipment.
Maintenance Access: Build in maintenance modes for battery replacement, hardware repairs, and firmware updates. The API should support temporarily taking individual lockers offline without affecting the rest of the fleet.
User Communication: Set clear expectations about what can and cannot be stored. Most systems prohibit valuables, perishables, and prohibited items. Display policies on locker doors and include in employee onboarding.
A well-integrated locker system removes one of the friction points in hot-desking, making it effortless for employees to store belongings securely while they work from any desk in the office.
Related Articles
- How to Set Up Hybrid Office Wayfinding System for Employees
- How to Create Hot Desking Floor Plan for Hybrid Office with
- How to Create Hybrid Office Quiet Zone Policy for Employees
- Hybrid Office Access Control System Upgrade for Flexible
- Meeting Room Booking System for Hybrid Office 2026
Built by theluckystrike — More at zovo.one