Computer Networks C# · MQTT Fall 2023 2-person project

Smart Lock

MQTT-based distributed lock system

A simulated smart lock built for a Computer Networks and Distributed Processing course. The lock runs as an MQTT client — subscribing to command topics, processing lock and unlock requests, and publishing responses back through the broker. Built in C# using MQTTnet with a Mosquitto broker.

MQTTnet Mosquitto Broker C# Pub / Sub Last Will Testament Topic Wildcards
01
Overview
MQTT pub/sub model and topic structure

MQTT is a lightweight publish/subscribe messaging protocol designed for constrained devices and low-bandwidth networks. Rather than direct communication between clients, all messages flow through a central broker. Publishers send messages to named topics, and any client subscribed to that topic receives the message — the publisher never needs to know who is listening.

In this project the Mosquitto broker sits at the center. The smart lock client subscribes to command topics and waits for messages. A separate publisher client sends commands to those topics, and a subscriber client listens on smartlock/response to see the lock's replies — simulating a real IoT deployment where the lock, the controller, and the monitor are all independent nodes.

Topic
Purpose
smartlock/lock
Lock request — send password as payload
smartlock/unlock
Unlock request — send password as payload
smartlock/status
Query current lock state — any payload
smartlock/temporary/activate
Enable temp password — send permanent password
smartlock/temporary/deactivate
Disable temp password — send permanent password
smartlock/response
Lock publishes all replies here
Topic wildcard
The lock subscribes to smartlock/temporary/+ with a single-level wildcard, catching both activate and deactivate in one subscription. The switch statement then handles each sub-topic individually.
02
Implementation
Event handler, temporary password, and Last Will Testament

Event-driven message handling — the core of the lock is an async event handler registered on ApplicationMessageReceivedAsync. Every time a message arrives on a subscribed topic, the handler reads the current lock state from a file, inspects the topic and payload, and builds a response. Lock state is persisted to disk so it survives application restarts — 1 for locked, 0 for unlocked.

Temporary password — a second password can be granted to a guest and activated/deactivated by the owner using the permanent password. Once used to lock or unlock, the temporary password automatically deactivates — a single-use access grant. This is enforced in the event handler by toggling a boolean and only resetting it after a successful operation.

smartlock/lock — event handler excerpt
case "smartlock/lock":
    if (locked) {
        lock_message = "Lock is already locked";
    } else {
        if (client_message == main_password) {
            // Write locked state to file
            File.WriteAllText(lock_file, "1");
            lock_message = "Lock has been locked";
        } else if (client_message == temp_password) {
            if (tempActivated) {
                File.WriteAllText(lock_file, "1");
                lock_message = "Locked with temp password";
                // Single-use — deactivate after use
                tempActivated = false;
            } else {
                lock_message = "Temp password is deactivated";
            }
        } else {
            lock_message = "Password does not match";
        }
    }
    break;
Last Will Testament
MQTT's Last Will Testament (LWT) lets a client pre-register a message with the broker at connection time. If the client disconnects ungracefully — a crash, power loss, or network failure — the broker automatically publishes that message on the specified topic. The smart lock registers a will on smartlock/response with the payload "The lock was broken or died", so any subscriber monitoring the lock gets notified immediately if the lock goes offline unexpectedly rather than silently.
MQTT client setup
// Last Will Testament registered at connect time
var options = new MqttClientOptionsBuilder()
    .WithTcpServer("127.0.0.1")
    .WithWillTopic("smartlock/response")
    .WithWillPayload("The lock was broken or died")
    .Build();

// Subscribe with wildcard for temp topics
.WithTopicFilter(f =>
    f.WithTopic("smartlock/temporary/+"))

// Publish response after every handled message
var reply = new MqttApplicationMessageBuilder()
    .WithTopic("smartlock/response")
    .WithPayload(lock_message)
    .Build();
await mqttClient.PublishAsync(reply);

Clean disconnect — when the lock exits normally it calls DisconnectAsync with explicit disconnect options, which sends a proper DISCONNECT packet to the broker. This tells the broker the client left intentionally, so the Last Will Testament is not triggered — the will only fires on ungraceful disconnects.

03
Demo
All command paths tested live

The demo runs four terminals side by side — the Mosquitto broker (top left), the smart lock client (top right), a subscriber listening on smartlock/response (bottom left), and a publisher sending commands (bottom right). Every major code path is exercised: permanent password, wrong password, and the full temporary password lifecycle — activate, use, and deactivate. Last will testament is also showcased.

Live demo — broker, lock client, publisher, and subscriber running simultaneously
← Previous Maze Search Next → Home