Mesh Dash API Documentation

Introduction

This document describes the HTTP API provided by the Enhanced Mesh Dash server (Version 2.4.5-auth). The API allows you to retrieve current network status, historical data, interact with the Meshtastic network by sending messages or triggering actions, and manage server-side features like task scheduling, auto-replies, and system configuration.

Endpoints generally return data in JSON format unless otherwise specified (e.g., Server-Sent Events or specific text-only responses). Authentication is required for most HTML page-serving endpoints and is handled via an access_token cookie obtained through the /login page. API endpoints under /api/*, as currently defined, do not enforce this cookie-based authentication but may be secured by other means (e.g., network-level restrictions) in a production environment.

Authentication

The dashboard's web pages (e.g., /, /map) are protected and require authentication. The system uses a cookie-based authentication mechanism. Upon successful login via the /login endpoint, an access_token HTTP-only cookie is set. This cookie must be sent by the browser for subsequent requests to protected pages.

API endpoints under /api/* currently do not have this specific cookie-based authentication dependency. They are generally open but would typically be protected by network configuration or a reverse proxy with its own authentication layer in a production deployment if external access is permitted.

GET /login

Serves the HTML login page. This page is not protected.

How it works: Reads and returns the content of static/login.html. If an error query parameter is present (e.g., /login?error=Invalid%20credentials), the error message is injected into the HTML page.

Query Parameters:

ParameterTypeDescription
errorstringOptional. An error message to display on the login page.

Response: HTML content of the login page.

POST /login

Processes user login credentials submitted via a form.

How it works:

  1. Receives username and password from the form data.
  2. Retrieves the user from the database using db_manager.get_user(username).
  3. Verifies the provided password against the stored hashed password using verify_password().
  4. If authentication is successful, it creates a JWT access token using create_access_token().
  5. Sets an HTTP-only cookie named access_token containing the JWT (prefixed with "Bearer ").
  6. Redirects the user to the main dashboard page (/) on success, or back to /login with an error message on failure.

Request Body (application/x-www-form-urlencoded):

ParameterTypeDescription
usernamestringRequired. The user's username.
passwordstringRequired. The user's password.

Responses:

  • 302 Found: Redirects to / on successful login (with access_token cookie set).
  • 302 Found: Redirects to /login?error=Invalid%20username%20or%20password on authentication failure.

GET /logout

Logs the current user out by clearing the authentication cookie.

How it works: Deletes the access_token cookie and redirects the user to the /login page.

Responses:

  • 302 Found: Redirects to /login.

Real-time Updates (Server-Sent Events)

GET /sse

Establishes a Server-Sent Events (SSE) connection. Once connected, the server will push real-time updates to the client. Upon connection, an initial state dump (connection status, local node info, full node list, stats, recent packets) is sent.

How it works: The client makes a GET request to this endpoint. The server keeps the connection open and sends events as they occur. This endpoint is typically not protected by the standard cookie-based redirect authentication to allow EventSource clients to connect directly.

Events Streamed:

  • connection_status: Updates on connection state to the Meshtastic device. Data: string (e.g., "Connected", "Disconnected", "Error", "Connecting", "Initializing").
  • local_node_info: Information about the node directly connected to the server. Data: object or null. Structure includes node_id, node_num, name, firmware, hardware, battery, voltage, channels_json (JSON string of channel settings), position.
  • nodes: Sent initially with a list of all known nodes. Data: Array<ApiNodeData>.
  • node_update: Sent when information about a specific node changes. Data: ApiNodeData object.
  • packet: Sent whenever a new packet is processed (received from mesh or logged as sent by this dashboard). Data: ApiPacketData object.
  • stats: Periodic updates of session statistics. Data: object (counters for packets, messages, nodes, elapsed time, etc.).
  • error: Sent when a server-side Meshtastic-related error occurs. Data: string (error message) or null.

A comment : heartbeat may be sent periodically (e.g., every 20 seconds if no other data) to keep the connection alive.

Client-Side JavaScript Example:


const evtSource = new EventSource("/sse"); // Assuming same origin

evtSource.onopen = function() {
  console.log("SSE Connection opened.");
};

evtSource.onmessage = function(event) {
  // Generic messages (if any) or for debugging
  console.log("Received generic SSE message:", event.id, event.type, event.data);
};

evtSource.addEventListener("packet", function(event) {
  try {
    const packetData = JSON.parse(event.data);
    console.log("Packet Event (ID: " + event.id + "):", packetData);
    // Update your UI with packetData
  } catch (e) {
    console.error("Error parsing packet event data:", e, event.data);
  }
});

evtSource.addEventListener("node_update", function(event) {
  try {
    const nodeData = JSON.parse(event.data);
    console.log("Node Update Event (ID: " + event.id + "):", nodeData);
    // Update your UI with nodeData
  } catch (e) {
    console.error("Error parsing node_update event data:", e, event.data);
  }
});

// Add listeners for "connection_status", "local_node_info", "stats", "error" similarly.

evtSource.onerror = function(err) {
  console.error("EventSource error:", err);
  // Handle reconnection logic if necessary
};

Main API - Current State

These endpoints provide information about the current state of the network and server as known by the application.

GET /api/status

Retrieves the current connection status to the Meshtastic device, information about the local (gateway) node, the last recorded error message, and the server's current Unix timestamp.

How it works: Reads directly from the meshtastic_data in-memory store.

Response Body (application/json):

{
  "connection_status": "Connected",
  "local_node_info": {
    "node_id": "!aabbccdd",
    "node_num": 2864434397,
    "name": "Gateway Node Name",
    "firmware": "2.2.21.0000000",
    "hardware": "RAK4631",
    "battery": 100,
    "voltage": 4.123,
    "channels_json": "[{\"index\":0,\"role\":\"PRIMARY\",\"settings\":{\"name\":\"Primary\",\"psk\":\"secret\",\"modemConfig\":\"Bw125Cr45Sf128\",\"channelId\":null,\"numericId\":0}}]",
    "position": {"latitude": 34.0522, "longitude": -118.2437, "altitude": 71, "time": 1714006300}
  },
  "last_error": null,
  "server_time_unix": 1714006345.123
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/status"

GET /api/stats

Retrieves current session statistics, such as packet counts, number of unique nodes seen during the session, and session duration.

How it works: Reads and formats statistics from the meshtastic_data.stats dictionary.

Response Body (application/json): An object containing various counters.

{
  "packets_received_session": 150,
  "text_messages_session": 25,
  "position_updates_session": 50,
  "telemetry_reports_session": 60,
  "user_info_updates_session": 5,
  "waypoint_updates_session": 0,
  "other_packets_session": 10,
  "start_time": 1714000000.123,
  "nodes_seen_session": 5,
  "channels_seen_session": 2,
  "elapsed_time_session": 6345.123
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/stats"

GET /api/nodes

Retrieves a dictionary of all currently known nodes from the server's in-memory cache. Data for each node is structured according to the ApiNodeData model.

How it works: Iterates through meshtastic_data.nodes and maps each entry using _map_node_to_api.

Response Body (application/json): A dictionary where keys are Node IDs (string, e.g., !aabbccdd) and values are ApiNodeData objects.

{
  "!aabbccdd": {
    "node_id": "!aabbccdd",
    "node_num": 2864434397,
    "user": {"longName": "Node Alpha", "shortName": "Alpha", "macaddr": "aa:bb:cc:dd:ee:ff", "hwModel": "TBEAM"},
    "long_name": "Node Alpha",
    "short_name": "Alpha",
    "macaddr": "aa:bb:cc:dd:ee:ff",
    "hw_model": "TBEAM",
    "firmware_version": "2.2.21.0000000",
    "role": "CLIENT_ROUTER",
    "is_local": false,
    "last_heard": 1714006300,
    "snr": 10.5,
    "rssi": -75,
    "battery_level": 80,
    "voltage": 3.9,
    "channel_utilization": 15.5,
    "air_util_tx": 2.1,
    "latitude": 34.0522,
    "longitude": -118.2437,
    "altitude": 71,
    "position_time": 1714006300,
    "telemetry_time": 1714006200,
    "created_at": "2023-05-01T10:00:00",
    "updated_at": "2023-05-18T12:30:00",
    "position": {"time": 1714006300, "latitude": 34.0522, "longitude": -118.2437, "altitude": 71},
    "deviceMetrics": {"time": 1714006200, "batteryLevel": 80, "voltage": 3.9, "channelUtilization": 15.5, "airUtilTx": 2.1}
  }
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/nodes"

GET /api/nodes/{node_id}

Retrieves the current state of a specific node by its ID, structured as an ApiNodeData object.

How it works: Looks up the node in meshtastic_data.nodes and maps it using _map_node_to_api.

Path Parameters:

ParameterTypeDescription
node_idstringRequired. The ID of the node to retrieve (e.g., !aabbccdd). Remember to URL-encode the ! as %21.

Responses:

  • 200 OK: JSON object (ApiNodeData) representing the node.
  • 404 Not Found: If the specified node_id is not found.
  • 500 Internal Server Error: If there's an error processing the node data.

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/nodes/%21aabbccdd"

GET /api/packets

Retrieves the most recent packets stored in the server's limited in-memory cache (a deque). Packets are structured as ApiPacketData objects.

How it works: Accesses the meshtastic_data.packets deque.

Query Parameters:

ParameterTypeDescription
limitintegerOptional, default: 50. Maximum number of recent packets to return. Min: 1, Max: value of MAX_PACKETS_IN_MEMORY (e.g., 200).

Response Body (application/json): List[ApiPacketData]

[
  {
    "event_id": "pkt_1672531200123456789_0",
    "timestamp": 1672531200.123,
    "rxTime": 1672531200,
    "fromId": "!aabbccdd",
    "toId": "^all",
    "channel": 0,
    "rxSnr": 8.5,
    "rxRssi": -80,
    "hopLimit": 3,
    "decoded": {"portnum": "TEXT_MESSAGE_APP", "payload": "Hello Mesh!"},
    "raw": {"from": 2864434397, "to": 4294967295, "channel": 0, "...": "other raw fields"},
    "app_packet_type": "Message",
    "wantAck": false
  }
]

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/packets?limit=10"

Main API - History (Database Queries)

These endpoints query the SQLite database for historical data.

GET /api/packets/history

Retrieves historical packets directly from the database, ordered from most recent.

How it works: Calls db_manager.get_recent_packets which queries the packets table.

Query Parameters:

ParameterTypeDescription
limitintegerOptional, default: 100. Maximum number of historical packets to return. Min: 1, Max: 10000.

Response Body (application/json): List[ApiPacketData] (similar structure to /api/packets).

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/packets/history?limit=200"

GET /api/messages/history

Retrieves historical text messages from the database, ordered from most recent, with several filtering options.

How it works: Calls db_manager.get_messages which queries the messages table.

Query Parameters:

ParameterTypeDescription
from_idstringOptional. Filter by sender node ID (e.g., %21aabbccdd).
to_idstringOptional. Filter by recipient node ID (e.g., %21aabbccdd or %5Eall for broadcast, which maps to !ffffffff in DB).
channelintegerOptional. Filter by Meshtastic channel index (0-7).
start_timefloatOptional. Unix timestamp (seconds); only messages at or after this time.
end_timefloatOptional. Unix timestamp (seconds); only messages at or before this time.
limitintegerOptional, default: 100. Maximum number of messages to return. Min: 1, Max: 5000.

Response Body (application/json): List[ApiMessageData]

[
  {
    "id": 101,
    "packet_event_id": "pkt_1672531200123456789_0",
    "from_id": "!aabbccdd",
    "to_id": "!ffffffff",
    "channel": 0,
    "text": "Hello Mesh!",
    "timestamp": 1672531200.123,
    "rx_snr": 8.5,
    "rx_rssi": -80,
    "created_at": "2023-05-01T10:00:00.123Z"
  }
]

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/messages/history?from_id=%21aabbccdd&limit=50"

GET /api/nodes/{node_id}/history/{history_type}

Retrieves position or telemetry history for a specific node from the database.

How it works: Calls db_manager.get_node_history which queries the positions or telemetry table.

Path Parameters:

ParameterTypeDescription
node_idstringRequired. The ID of the node (e.g., %21aabbccdd).
history_typestringRequired. Must be either positions or telemetry.

Query Parameters:

ParameterTypeDescription
start_timefloatOptional. Unix timestamp (seconds); only records at or after this time.
end_timefloatOptional. Unix timestamp (seconds); only records at or before this time.
limitintegerOptional, default: 1000. Maximum number of history records to return. Min: 1, Max: 10000.

Response Body (application/json): List[ApiNodePositionHistory] or List[ApiNodeTelemetryHistory] depending on history_type.

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/nodes/%21aabbccdd/history/positions?limit=10"

GET /api/nodes/{node_id}/count/{item_type}

Retrieves the total count of specific items (messages sent, positions, telemetry records) associated with a given node ID from the database history, optionally filtered by time.

How it works: Calls db_manager.count_node_items which performs a COUNT query on the relevant table.

Path Parameters:

ParameterTypeDescription
node_idstringRequired. The ID of the node (e.g., %21aabbccdd).
item_typestringRequired. Type of item to count. Must be one of: messages_sent, positions, or telemetry.

Query Parameters:

ParameterTypeDescription
start_timefloatOptional. Unix timestamp (seconds) for filtering.
end_timefloatOptional. Unix timestamp (seconds) for filtering.

Response Body (application/json - Model: NodeItemCountResponse):

{
  "node_id": "!aabbccdd",
  "item_type": "messages_sent",
  "count": 125,
  "start_time_filter": null,
  "end_time_filter": null
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/nodes/%21aabbccdd/count/messages_sent"

GET /api/counts/totals

Retrieves the total historical counts for messages sent, positions recorded, and telemetry records across *all* nodes stored in the database.

How it works: Calls db_manager.count_node_items for each item type with node_id=None.

Response Body (application/json - Model: ApiTotalCountsResponse):

{
  "total_messages": 5678,
  "total_positions": 12034,
  "total_telemetry": 9850
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/counts/totals"

GET /api/metrics/averages

Retrieves the most recently calculated average mesh metrics (SNR, RSSI, node count) and a history of these averages from the database.

How it works: Calls db_manager.get_most_recent_average_metrics and db_manager.get_average_metrics_history.

Query Parameters:

ParameterTypeDescription
limitintegerOptional, default: 100. Maximum number of historical average records to return. Min: 1, Max: 5000.

Response Body (application/json - Model: ApiAverageMetricsResponse):

{
  "most_recent": {
    "id": 5,
    "timestamp": 1714006000.0,
    "average_snr": 7.5,
    "average_rssi": -82.1,
    "node_count": 4,
    "created_at": "2023-05-18T12:26:40"
  },
  "history": [
    {
      "id": 5,
      "timestamp": 1714006000.0,
      "average_snr": 7.5,
      "average_rssi": -82.1,
      "node_count": 4,
      "created_at": "2023-05-18T12:26:40"
    }
  ]
}

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/metrics/averages?limit=10"

Main API - Actions

These endpoints allow performing actions on the Meshtastic network or server.

POST /api/messages

Queues a text message to be sent via the connected Meshtastic device. The sent message is also logged to the database as if it were a received packet from the local node.

How it works: Calls interface.sendText and then logs a constructed packet to the DB via meshtastic_data.add_packet.

Request Body (application/json - Model: MessageRequest):

{
  "message": "Hello from the API!",
  "destination": "!aabbccdd",  // Node ID, or null/^all for broadcast
  "channel": 0               // Channel index (0-7, default 0)
}

Responses:

  • 202 Accepted: Message queued. Response: {"status": "queued", "detail": "Message sent..."}
  • 422 Unprocessable Entity: If message text is empty.
  • 503 Service Unavailable: Not connected to Meshtastic device.
  • 500 Internal Server Error: If an unexpected error occurs during sending or logging.

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/messages" \
-H "Content-Type: application/json" \
-d '{
  "message": "Hello via API call!",
  "destination": "^all",
  "channel": 0
}'

POST /api/hook

A specific endpoint designed for simple external triggers (webhooks) to send a message to a specific node ID. The message is also logged to the database.

How it works: Similar to /api/messages but with a more constrained request model (HookMessageRequest). Requires node_id to start with !.

Request Body (application/json - Model: HookMessageRequest):

{
  "node_id": "!aabbccdd",       // Required, must start with '!'
  "message": "Webhook message content", // Required
  "channel": 0                // Optional channel index (default: 0)
}

Responses:

  • 202 Accepted: Message queued. Response: {"status": "queued", "detail": "Hook message sent..."}
  • 422 Unprocessable Entity: If validation fails (e.g., empty message, invalid node_id format).
  • 503 Service Unavailable: Not connected to Meshtastic device.

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/hook" \
-H "Content-Type: application/json" \
-d '{
  "node_id": "!fedcba98",
  "message": "Alert from webhook!",
  "channel": 1
}'

POST /api/system/restart

Restarts the Meshtastic Dashboard server application.

How it works: Performs a graceful shutdown of background tasks and the Meshtastic interface, then re-executes the script using os.execv. The client will likely experience a connection drop.

Request Body: None.

Responses:

  • 202 Accepted: Server restart initiated. Response: {"message": "Server is restarting..."}. This response may not be fully received by the client due to the immediate restart.
  • 500 Internal Server Error: If the restart command (os.execv) fails.

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/system/restart"

Main API - URL Content Extraction

These endpoints are for fetching and processing content from external URLs.

POST /extract

Fetches content from a given URL, parses the HTML, and extracts identifiable text blocks. It can return all blocks or a specific block, optionally as plain text.

How it works: Uses `httpx` (via `requests` in the provided code, wrapped in `asyncio.to_thread`) to fetch the URL and `BeautifulSoup` to parse and extract text blocks. This is a synchronous operation run in a thread to prevent blocking the main event loop.

Request Body (application/json - Model: URLRequest):

{
  "url": "https://example.com/statuspage",
  "block_id": null,  // Optional: integer, index of the specific block to extract
  "text_only": false // Optional: boolean, if true and block_id is set, returns plain text
}

Responses:

  • 200 OK:
    • If block_id is specified and text_only is true: text/plain response with the text of the block.
    • If block_id is specified and text_only is false: JSON object {"url": "...", "block_id": ..., "block": {"element_type": "...", "text": "..."}}.
    • If block_id is not specified: JSON object {"url": "...", "total_blocks": ..., "blocks": [{"element_type": "...", "text": "..."}, ...]}.
  • 404 Not Found: If a specified block_id is out of range.
  • 502 Bad Gateway: If fetching or parsing the URL fails.
  • 500 Internal Server Error: For other unexpected errors.

Usage Example (cURL to get all blocks):

curl -X POST "http://localhost:8000/extract" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'

Usage Example (cURL to get specific block as text):

curl -X POST "http://localhost:8000/extract" \
-H "Content-Type: application/json" \
-d '{
  "url": "https://example.com",
  "block_id": 0,
  "text_only": true
}'

POST /monitor/website

Fetches a specific block of text content from a website, prepends a given prefix, and sends the combined text as a Meshtastic message. The sent message is also logged to the database.

How it works: Uses the same URL fetching/parsing logic as /extract. Then, it constructs a message and sends it via interface.sendText, logging the sent message to the DB.

Request Body (application/json - Model: WebsiteMonitorRequest):

{
  "url": "https://example.com/statuspage",
  "block_id": 0,                 // Integer index of the block to extract
  "prefix": "Status Update:",    // Text to prepend to the extracted content
  "node_id": "^all",             // Optional: destination Node ID or "^all" for broadcast
  "channel": 0                 // Optional: channel index (0-7, default 0)
}

Responses:

  • 200 OK: If successful. Response: {"success": true, "message": "Sent '...' to node '...'", "extracted_text": "..."}.
  • 400 Bad Request: If node_id format is invalid.
  • 404 Not Found: If the specified block_id is out of range.
  • 503 Service Unavailable: Not connected to Meshtastic device.
  • 502 Bad Gateway / 500 Internal Server Error: For URL fetching/parsing errors or other send failures.

Usage Example (cURL):

curl -X POST "http://localhost:8000/monitor/website" \
-H "Content-Type: application/json" \
-d '{
  "url": "https://example-status.com",
  "block_id": 1,
  "prefix": "Web Alert:",
  "node_id": "!12345678",
  "channel": 0
}'

Included Router APIs

The main application includes functionality from other modules using FastAPI's APIRouter. These API endpoints are generally open but would typically be secured by other means (e.g., network firewall, reverse proxy authentication) if exposed externally.

System Config API (system.py)

Prefix: /api/system/config
Tags: "System Config API"

Manages the dashboard's own configuration settings, stored in the .mesh-dash_config file. Changes typically require a server restart to take full effect, which can be triggered via /api/system/restart (main API) or handled by the /initial-setup endpoint.

GET /

Reads and returns all key-value pairs from the .mesh-dash_config file.

How it works: Reads the config file synchronously in a thread using read_dash_config.

Response Body (application/json): Dict[str, str] representing the configuration.

{
  "MESHTASTIC_HOST": "192.168.1.50",
  "LOG_LEVEL": "INFO",
  "SEND_LOCAL_NODE_LOCATION": "true"
}

Responses:

  • 200 OK
  • 404 Not Found: If the config file does not exist.
  • 500 Internal Server Error: If there's an error reading the file.

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/system/config/"
PUT /{key_name}

Updates the value of a specific key in the .mesh-dash_config file. If the key does not exist, it will be added.

How it works: Reads the existing config, updates or adds the key, and rewrites the file synchronously in a thread using write_dash_config. Preserves comments and formatting where possible.

Path Parameters:

ParameterTypeDescription
key_namestringRequired. The configuration key to update (e.g., MESHTASTIC_HOST).

Request Body (application/json - Model: ConfigUpdateRequest):

{ "value": "new_config_value" }

Response Body (application/json): Dict[str, str] showing the updated key-value pair.

{ "MESHTASTIC_HOST": "10.0.0.100" }

Responses:

  • 200 OK
  • 500 Internal Server Error: If there's an error writing the file.

Usage Example (cURL):

curl -X PUT "http://localhost:8000/api/system/config/MESHTASTIC_HOST" \
-H "Content-Type: application/json" \
-d '{"value": "10.0.0.100"}'
POST /initial-setup

Handles the initial setup data submission from the first-run wizard. Writes admin user credentials (INITIAL_ADMIN_USERNAME, INITIAL_ADMIN_PASSWORD) and selected privacy/community settings to the .mesh-dash_config file. After successfully writing the configuration, it triggers an automatic server restart to apply changes and allow the main app to create the initial admin user from these config values.

How it works: Constructs a dictionary of configuration key-value pairs from the payload and writes them to the config file using write_dash_config. If a static/.new file exists (indicator for first setup), it's removed. Then, schedules a deferred task to restart the server via os.execv.

Request Body (application/json - Model: InitialSetupPayload):

{
  "adminUser": {
    "username": "admin",
    "password": "securepassword123"
  },
  "configValues": {
    "SEND_LOCAL_NODE_LOCATION": "true",
    "SEND_OTHER_NODES_LOCATION": "false",
    "COMMUNITY_API": "true",
    "LOCATION_OFFSET_ENABLED": "false",
    "LOCATION_OFFSET_METERS": "0.0"
  },
  "rawSelections": {
     "operatingMode": "private_network_operator",
     "joinCommunity": "yes_anonymous",
     "shareLocation": "yes",
     "shareDetectedNodes": "no"
  }
}

Responses:

  • 200 OK: If the configuration is successfully written and restart is scheduled. Response: {"message": "Initial setup data received...", "restart_scheduled": true}. The client may not fully receive this if the restart is very fast.
  • 500 Internal Server Error: If there's an error writing the config file or if the restart command fails.

Note: This endpoint is typically used by the initial setup wizard and may not require prior authentication if the static/.new file exists, allowing setup before login is possible.

POST /request-restart

This endpoint is informational. It acknowledges that a manual server restart is needed for certain configuration changes to take full effect (e.g., changes made via direct file edit or other non-restarting API calls). It does not programmatically restart the server.

How it works: Simply returns a message advising the user to restart the service.

Request Body: None.

Response Body (application/json):

{
  "message": "Acknowledgement: For all recent configuration changes to be fully applied, please restart the MeshDash service..."
}

Responses:

  • 200 OK

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/system/config/request-restart"

Tasks API (tasks_api.py)

Prefix: /api/tasks
Tags: "Tasks API"

Manages scheduled tasks (e.g., sending messages, monitoring websites) stored in the tasks.db SQLite database. These tasks are executed by the separate task_scheduler.py script.

POST /

Creates a new scheduled task.

How it works: Inserts a new record into the tasks table in tasks.db.

Request Body (application/json - Model: TaskCreate):

{
  "nodeId": "!aabbccdd",         // Target node ID for the task
  "taskType": "message",       // Type of task (e.g., "message", "website_monitor")
  "actionPayload": "Scheduled hello!", // JSON string or plain text for the action
  "cronString": "0 12 * * *",  // Cron string for scheduling
  "enabled": true              // Optional, defaults to true
}

Response Body (application/json - Model: TaskInDB): The created task object, including its new id.

Responses:

  • 201 Created
  • 422 Unprocessable Entity: If input data is invalid.
  • 500 Internal Server Error: For database errors.

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/tasks/" \
-H "Content-Type: application/json" \
-d '{"nodeId": "!aabbccdd", "taskType": "message", "actionPayload": "Good morning!", "cronString": "0 8 * * *"}'
GET /

Lists all scheduled tasks from tasks.db.

How it works: Queries all records from the tasks table.

Response Body (application/json): List[TaskInDB]

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/tasks/"
GET /{task_id}

Retrieves a specific scheduled task by its ID.

How it works: Queries the tasks table for a specific ID.

Path Parameters:

ParameterTypeDescription
task_idintegerRequired. The ID of the task to retrieve.

Response Body (application/json - Model: TaskInDB): The requested task object.

Responses:

  • 200 OK
  • 404 Not Found: If the task ID does not exist.

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/tasks/1"
PUT /{task_id}

Updates an existing scheduled task. Allows partial updates.

How it works: Updates the specified fields for a task in the tasks table.

Path Parameters:

ParameterTypeDescription
task_idintegerRequired. The ID of the task to update.

Request Body (application/json - Model: TaskUpdate): Fields to update.

{
  "cronString": "0 10 * * MON",
  "enabled": false
}

Response Body (application/json - Model: TaskInDB): The updated task object.

Responses:

  • 200 OK
  • 400 Bad Request: If no update data is provided.
  • 404 Not Found: If the task ID does not exist.
  • 422 Unprocessable Entity: If input data is invalid.

Usage Example (cURL):

curl -X PUT "http://localhost:8000/api/tasks/1" \
-H "Content-Type: application/json" \
-d '{"cronString": "0 10 * * MON", "enabled": false}'
DELETE /{task_id}

Deletes a scheduled task by its ID.

How it works: Removes the task record from the tasks table.

Path Parameters:

ParameterTypeDescription
task_idintegerRequired. The ID of the task to delete.

Responses:

  • 204 No Content: Task deleted successfully.
  • 404 Not Found: If the task ID does not exist.

Usage Example (cURL):

curl -X DELETE "http://localhost:8000/api/tasks/1"
GET /sensors/{node_id}

Deprecated. Example endpoint to get available sensors for a node. Currently returns a hardcoded list.

Path Parameters:

ParameterTypeDescription
node_idstringRequired. The ID of the node (e.g., %21aabbccdd). Currently unused by the hardcoded response.

Response Body (application/json): List[ApiSensorInfo]

[
  {"id": "bed_temp", "name": "Bedroom Temp"},
  {"id": "hall_motion", "name": "Hallway Motion"}
]

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/tasks/sensors/%21aabbccdd"

Auto Reply API (auto_reply_api.py)

Prefix: /api/auto_reply
Tags: "Auto Reply API"

Manages auto-reply rules for incoming Meshtastic messages. Rules are stored in the main application's database (meshtastic_data.db, in the auto_reply_rules table).

POST /rules

Creates a new auto-reply rule.

How it works: Validates the input and calls db_add_auto_reply_rule to insert the rule into the database.

Request Body (application/json - Model: AutoReplyRuleCreateUpdate):

{
  "trigger_phrase": "status report",
  "match_type": "contains",         // "contains", "exact", or "regex"
  "response_message": "All systems nominal.",
  "cooldown_seconds": 300,        // Time in seconds
  "is_enabled": true
}

Response Body (application/json - Model: AutoReplyRuleResponse): The created rule object, including its new id.

Responses:

  • 201 Created
  • 422 Unprocessable Entity: If input data (e.g., invalid regex, empty phrase) is invalid.
  • 500 Internal Server Error: For database errors.

Usage Example (cURL):

curl -X POST "http://localhost:8000/api/auto_reply/rules" \
-H "Content-Type: application/json" \
-d '{"trigger_phrase": "help", "match_type": "exact", "response_message": "See docs at example.com/help", "cooldown_seconds": 60, "is_enabled": true}'
GET /rules

Lists all auto-reply rules. Can be filtered by enabled status.

How it works: Calls db_get_auto_reply_rules.

Query Parameters:

ParameterTypeDescription
only_enabledbooleanOptional. If true, only enabled rules are returned. If false, only disabled. If not provided, all rules are returned.

Response Body (application/json): List[AutoReplyRuleResponse]

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/auto_reply/rules?only_enabled=true"
GET /rules/{rule_id}

Retrieves a specific auto-reply rule by its ID.

How it works: Calls db_get_auto_reply_rule_by_id.

Path Parameters:

ParameterTypeDescription
rule_idintegerRequired. The ID of the auto-reply rule.

Response Body (application/json - Model: AutoReplyRuleResponse): The requested rule object.

Responses:

  • 200 OK
  • 404 Not Found: If the rule ID does not exist.

Usage Example (cURL):

curl -X GET "http://localhost:8000/api/auto_reply/rules/1"
PUT /rules/{rule_id}

Updates an existing auto-reply rule.

How it works: Calls db_update_auto_reply_rule.

Path Parameters:

ParameterTypeDescription
rule_idintegerRequired. The ID of the auto-reply rule to update.

Request Body (application/json - Model: AutoReplyRuleCreateUpdate): Fields to update.

Response Body (application/json - Model: AutoReplyRuleResponse): The updated rule object.

Responses:

  • 200 OK
  • 404 Not Found: If the rule ID does not exist.
  • 422 Unprocessable Entity: If input data is invalid.

Usage Example (cURL):

curl -X PUT "http://localhost:8000/api/auto_reply/rules/1" \
-H "Content-Type: application/json" \
-d '{"trigger_phrase": "help please", "match_type": "contains", "response_message": "See docs at example.com/help or ask a human!", "cooldown_seconds": 120, "is_enabled": true}'
DELETE /rules/{rule_id}

Deletes an auto-reply rule by its ID.

How it works: Calls db_delete_auto_reply_rule.

Path Parameters:

ParameterTypeDescription
rule_idintegerRequired. The ID of the auto-reply rule to delete.

Response Body (application/json):

{ "detail": "Auto-reply rule with ID {rule_id} successfully deleted." }

Responses:

  • 200 OK: If deletion was successful.
  • 404 Not Found: If the rule ID does not exist.

Usage Example (cURL):

curl -X DELETE "http://localhost:8000/api/auto_reply/rules/1"
PUT /rules/bulk/enable

Enables or disables all auto-reply rules at once.

How it works: Directly updates the is_enabled column for all rules in the auto_reply_rules table.

Query Parameters:

ParameterTypeDescription
enablebooleanRequired. Set to true to enable all rules, false to disable all rules.

Response Body (application/json):

{ "detail": "Successfully set 'is_enabled' to {enable_value} for {rows_affected} rules." }

Responses:

  • 200 OK
  • 500 Internal Server Error: For database errors.

Usage Example (cURL to enable all):

curl -X PUT "http://localhost:8000/api/auto_reply/rules/bulk/enable?enable=true"