Feature: Access Logging

Complexity: 🟡 Medium Hardware Required: ✅ None (uses ESP32-C3 flash) User Value: ⭐⭐⭐ Essential

Overview

Implement comprehensive logging of all access attempts, both successful and failed. Store logs locally using ESP32-C3’s flash memory (NVS/SPIFFS), with options for remote transmission via built-in WiFi. Essential for security auditing and troubleshooting.

Benefits

  • Security audit trail
  • Usage pattern analysis
  • Troubleshooting system issues
  • Compliance with security policies
  • Evidence in case of security incidents

Storage Options

NVS (Non-Volatile Storage)

  • Built into ESP32-C3
  • 24KB available
  • Perfect for configuration and recent events
  • Survives deep sleep and power cycles
  • ~400 log entries capacity

SPIFFS (Flash File System)

  • Built into ESP32-C3
  • 1.5MB available
  • File-based storage
  • CSV export capability
  • ~75,000 log entries capacity

Remote Storage (WiFi)

  • Real-time transmission
  • Unlimited capacity
  • Cloud integration options
  • MQTT/HTTP/WebSocket support

SD Card Module (Optional)

  • Massive storage capacity
  • Removable for analysis
  • Requires SPI connection
  • ~$5 for module + SD card

Implementation Checklist

Phase 1: Log Entry Structure

  • Define log entry format:
    struct LogEntry {
        uint32_t timestamp;      // Unix timestamp
        uint8_t eventType;       // Access granted/denied/error
        uint8_t uid[10];        // Card UID (up to 10 bytes)
        uint8_t uidLength;      // 4 or 7 bytes typically
        uint8_t accessLevel;    // If using access levels
        uint8_t relayActivated; // Which relay was triggered
        int8_t rssi;           // WiFi signal strength
        uint8_t batteryLevel;   // Battery percentage
        uint16_t checksum;      // Data integrity check
    };
    
  • Event type constants:
    enum EventType {
        EVENT_ACCESS_GRANTED = 0x01,
        EVENT_ACCESS_DENIED = 0x02,
        EVENT_INVALID_CARD = 0x03,
        EVENT_EXPIRED_CARD = 0x04,
        EVENT_TIME_RESTRICTED = 0x05,
        EVENT_EMERGENCY_UNLOCK = 0x06,
        EVENT_REMOTE_UNLOCK = 0x07,
        EVENT_BLE_UNLOCK = 0x08,
        EVENT_WEB_UNLOCK = 0x09,
        EVENT_SYSTEM_STARTUP = 0x0A,
        EVENT_SYSTEM_ERROR = 0x0B,
        EVENT_TAMPER_ALERT = 0x0C,
        EVENT_OTA_UPDATE = 0x0D,
        EVENT_CONFIG_CHANGE = 0x0E
    };
    

Phase 2: ESP32-C3 Storage Implementation

  • Create LogController class:
    class LogController {
    private:
        Preferences preferences;
        const char* nvs_namespace = "access_log";
        File spiffs_log;
        uint32_t log_index;
    
    public:
        bool begin();
        bool logEvent(const LogEntry& entry);
        uint32_t getLogCount();
        bool readLog(uint32_t index, LogEntry& entry);
        bool exportToCSV(const char* filename);
        bool clearLogs();
        bool syncToCloud();
    };
    

Phase 3: NVS Implementation

  • Circular buffer in NVS:
    bool LogController::logToNVS(const LogEntry& entry) {
        preferences.begin(nvs_namespace, false);
    
        // Get current index
        uint32_t index = preferences.getUInt("index", 0);
    
        // Store entry
        char key[16];
        snprintf(key, sizeof(key), "log_%d", index % MAX_NVS_LOGS);
        preferences.putBytes(key, &entry, sizeof(entry));
    
        // Update index
        preferences.putUInt("index", index + 1);
        preferences.putUInt("count", min(index + 1, MAX_NVS_LOGS));
    
        preferences.end();
        return true;
    }
    

Phase 4: SPIFFS Implementation

  • File-based logging:
    bool LogController::logToSPIFFS(const LogEntry& entry) {
        // Create monthly log files
        char filename[32];
        struct tm timeinfo;
        getLocalTime(&timeinfo);
        strftime(filename, sizeof(filename), "/logs/%Y-%m.log", &timeinfo);
    
        // Append binary entry
        File file = SPIFFS.open(filename, FILE_APPEND);
        if (!file) return false;
    
        size_t written = file.write((uint8_t*)&entry, sizeof(entry));
        file.close();
    
        // Check if we need rotation
        checkLogRotation();
    
        return written == sizeof(entry);
    }
    

Phase 5: Remote Logging

  • WiFi transmission:
    bool LogController::sendToServer(const LogEntry& entry) {
        if (!WiFi.isConnected()) return false;
    
        // Format as JSON
        StaticJsonDocument<256> doc;
        doc["timestamp"] = entry.timestamp;
        doc["event"] = getEventName(entry.eventType);
        doc["uid"] = uidToString(entry.uid, entry.uidLength);
        doc["rssi"] = WiFi.RSSI();
    
        // Send via HTTP POST
        HTTPClient http;
        http.begin(LOG_SERVER_URL);
        http.addHeader("Content-Type", "application/json");
    
        String json;
        serializeJson(doc, json);
        int httpCode = http.POST(json);
        http.end();
    
        return httpCode == 200;
    }
    

Phase 6: Log Management

  • Web Interface:
    void setupLogWebEndpoints() {
        // View logs
        server.on("/api/logs", HTTP_GET, []() {
            String json = "[";
            LogEntry entry;
    
            for (int i = 0; i < getLogCount(); i++) {
                if (readLog(i, entry)) {
                    if (i > 0) json += ",";
                    json += entryToJSON(entry);
                }
            }
            json += "]";
    
            server.send(200, "application/json", json);
        });
    
        // Export CSV
        server.on("/api/logs/export", HTTP_GET, []() {
            server.sendHeader("Content-Disposition", "attachment; filename=logs.csv");
            server.send(200, "text/csv", exportLogsAsCSV());
        });
    }
    

Phase 7: Analytics & Reporting

  • Built-in Analytics:
    struct LogStats {
        uint32_t totalAccess;
        uint32_t uniqueUsers;
        uint32_t failedAttempts;
        uint32_t peakHour;
        float avgDoorOpenTime;
    
        void calculate() {
            // Process logs in SPIFFS
            File root = SPIFFS.open("/logs");
            File file = root.openNextFile();
    
            while (file) {
                processLogFile(file);
                file = root.openNextFile();
            }
        }
    };
    

Phase 8: Log Format Examples

CSV Export Format

Timestamp,Date,Time,Event,UID,User,AccessLevel,Relay,RSSI,Battery,Details
1704067200,2024-01-01,12:00:00,ACCESS_GRANTED,04:12:34:56:78:9A:BC,John Doe,USER,1,-45,85%,Door opened
1704067230,2024-01-01,12:00:30,ACCESS_DENIED,01:23:45:67,Unknown,NONE,0,-52,84%,Invalid card
1704067260,2024-01-01,12:01:00,REMOTE_UNLOCK,WEB_USER,Admin,ADMIN,1,-40,84%,Web interface

JSON Format (for remote transmission)

{
  "timestamp": 1704067200,
  "event": "ACCESS_GRANTED",
  "uid": "04:12:34:56:78:9A:BC",
  "user": "John Doe",
  "accessLevel": "USER",
  "relay": 1,
  "rssi": -45,
  "battery": 85,
  "location": "Front Door"
}

Memory Calculations

NVS (24KB available)

  • Header: 100 bytes
  • Per entry: 24 bytes
  • Capacity: ~400 entries

SPIFFS (1.5MB available)

  • System files: ~100KB
  • Per entry: 24 bytes (binary)
  • Per entry: ~100 bytes (CSV)
  • Capacity: ~50,000 entries (binary)

Cloud Storage

  • Unlimited capacity
  • Real-time access
  • Advanced analytics
  • Multi-site aggregation

Testing Checklist

  • Flash write performance
  • Deep sleep persistence
  • Power loss during write
  • SPIFFS fragmentation handling
  • WiFi transmission reliability
  • Time sync accuracy (NTP)
  • Web export functionality
  • Log rotation testing
  • Memory usage monitoring

Privacy & Security

  • Encrypted storage option
  • GDPR compliance features
  • Automatic anonymization
  • Role-based log access
  • Audit log of log access
  • Secure transmission (HTTPS)
  • Data retention policies

Power Optimization

  • Batch log uploads
  • Compress before transmission
  • Use MQTT for efficiency
  • Cache during WiFi outage
  • Deep sleep between uploads

Future Enhancements

  • WebSocket real-time streaming
  • Machine learning anomaly detection
  • Integration with security systems
  • Blockchain for tamper-proof logs
  • Edge analytics processing
  • Multi-site synchronization
  • Predictive access patterns

Copyright © 2025 DapperDivers. MIT License.