Datacake LNS Nodes
LoRaWAN Network Server integration nodes for monitoring gateway status and performance from The Things Stack. More LNS to follow.
Overview
The Datacake LNS (LoRaWAN Network Server) nodes provide seamless integration with The Things Stack (TTS) API, enabling you to:
🌐 Monitor gateway connection status in real-time
📊 Track uplink and downlink message counters
⏱️ Measure network latency and round-trip times
📍 Retrieve gateway location information
🔄 Query gateway details on-demand or at intervals
🚨 Build alerting systems for gateway offline events
Perfect for LoRaWAN network operators, IoT service providers, and anyone managing TTS gateways who needs programmatic access to gateway status.
Configuration
TTS Config
Configuration node for storing The Things Stack API credentials securely.
Settings
Name - Optional descriptive name for this configuration
Server URL - The URL of your TTS server
Community Edition:
https://eu1.cloud.thethings.network
Community Edition (US):
https://nam1.cloud.thethings.network
Community Edition (AU):
https://au1.cloud.thethings.network
Enterprise/Private: Your instance URL (e.g.,
https://thethings.example.com
)
API Key - Your TTS API key with gateway read permissions
How to Get Your API Key
Log in to The Things Stack Console
Go to your application or user settings
Navigate to API Keys
Click Add API Key
Required Rights:
RIGHT_GATEWAY_INFO
- Read gateway informationRIGHT_GATEWAY_STATUS_READ
- Read gateway status and statistics
Generate and copy the API key
Store it in the TTS Config node
⚠️ Important: Keep your API key secure. Never share it or commit it to version control.
Server URL Examples
The Things Network (Community):
Europe:
https://eu1.cloud.thethings.network
North America:
https://nam1.cloud.thethings.network
Australia:
https://au1.cloud.thethings.network
The Things Stack (Enterprise/Cloud):
Your dedicated instance URL
Format:
https://<tenant>.thethings.industries
or custom domain
Private Deployment:
Your self-hosted instance URL
TTS Gateway Node
Monitor LoRaWAN gateway status and connection statistics from The Things Stack.
Configuration
Gateway ID Source
Configured - Use a fixed gateway ID from the node configuration
From Message - Extract gateway ID dynamically from incoming messages
Gateway ID
The gateway ID to query (only visible when "Gateway ID Source" is set to "Configured").
Gateway ID Format:
Usually starts with
eui-
followed by the gateway EUIExample:
eui-b827ebfffe8b1234
Found in The Things Stack Console under your gateway details
Input Properties
When Gateway ID Source is "Configured":
msg.payload
- Any input triggers the query
When Gateway ID Source is "From Message":
msg.payload.gatewayId
- Gateway ID to query (preferred)msg.gatewayId
- Alternative location for gateway IDmsg.payload
(string) - Gateway ID as direct payload
Output Properties
msg.payload
object
Normalized gateway status data
msg.gatewayId
string
The gateway ID that was queried
Output Structure
{
"gateway_id": "eui-b827ebfffe8b1234",
"gateway_eui": "B827EBFFFE8B1234",
"name": "Office Building Gateway",
"description": "Main gateway for office building IoT sensors",
"location": {
"latitude": 52.52,
"longitude": 13.405,
"altitude": 45,
"source": "SOURCE_REGISTRY"
},
"latitude": 52.52,
"longitude": 13.405,
"altitude": 45,
"frequency_plan_id": "EU_863_870_TTN",
"frequency_plan_ids": ["EU_863_870_TTN"],
"status_public": true,
"location_public": true,
"attributes": {
"placement": "indoor",
"antenna_type": "omni"
},
"version_ids": {
"brand_id": "dragino",
"model_id": "dlos8",
"hardware_version": "1.0",
"firmware_version": "4.4.3"
},
"connected": true,
"connected_at": "2025-10-08T08:15:30.123Z",
"disconnected_at": null,
"protocol": "udp",
"uplink_count": 15234,
"downlink_count": 127,
"last_uplink_received_at": "2025-10-08T10:35:22.456Z",
"last_downlink_received_at": "2025-10-08T10:30:15.789Z",
"round_trip_times": {
"min": "12ms",
"max": "89ms",
"median": "34ms",
"count": 1250
},
"sub_bands": [
{
"min_frequency": "863000000",
"max_frequency": "870000000",
"downlink_utilization": 0.02
}
],
"_raw": {
"info": { /* Complete gateway info response */ },
"stats": { /* Complete connection stats response */ }
}
}
Status Display
The node provides real-time visual feedback:
Connected
🟢 Green dot
Gateway is online with uplink/downlink counts shown
Disconnected
🟡 Yellow ring
Gateway is offline or not reporting
Error
🔴 Red ring
Error occurred (API error, invalid config, etc.)
Fetching
🔵 Blue dot
Query in progress
Example Status:
Connected (↑15234 ↓127)
- Online with 15,234 uplinks and 127 downlinks
Connection Status Logic
A gateway is considered connected when:
connected_at
exists (has connected at least once)AND
disconnected_at
is null (not explicitly disconnected)
If connection stats are not available (404 response), the gateway is marked as not connected.
Use Cases & Examples
1. Periodic Gateway Monitoring
Monitor gateway status at regular intervals and alert when offline.
Flow:
[Inject: Every 5 minutes]
↓
[TTS Gateway Node]
Gateway ID: eui-b827ebfffe8b1234
↓
[Switch: Check connection status]
Property: msg.payload.connected
↓
[Branch 1: If false]
↓
[Function: Format alert]
msg.payload = {
subject: "Gateway Offline Alert",
text: `Gateway ${msg.payload.name} is offline.
Last heard: ${msg.payload.disconnected_at}
Gateway ID: ${msg.payload.gateway_id}`
};
return msg;
↓
[Email/SMS/Slack Alert]
[Branch 2: If true]
↓
[Debug: Log status (optional)]
Benefits:
Early detection of gateway failures
Proactive maintenance
Reduced downtime
Better network reliability
2. Gateway Performance Dashboard
Create a real-time dashboard showing gateway metrics.
Flow:
[Inject: Every 1 minute]
↓
[TTS Gateway Node]
↓
[Function: Extract metrics]
msg.status = msg.payload.connected ? "Online" : "Offline";
msg.uplinks = msg.payload.uplink_count || 0;
msg.downlinks = msg.payload.downlink_count || 0;
msg.latency = msg.payload.round_trip_times?.median || "N/A";
msg.lastSeen = msg.payload.last_uplink_received_at;
return msg;
↓
[Dashboard Nodes]
- Text: Gateway Status
- Gauge: Uplink Count
- Gauge: Downlink Count
- Text: Median Latency
- Text: Last Seen
Dashboard Widgets:
Connection status indicator (green/red)
Uplink/downlink counters
Latency gauge
Last activity timestamp
Signal strength trends
3. Multi-Gateway Fleet Monitoring
Monitor multiple gateways and aggregate status.
Flow:
[Inject: Every 5 minutes]
↓
[Function: Generate gateway list]
msg.payload = [
"eui-b827ebfffe8b1234",
"eui-a827ebfffe9c5678",
"eui-c827ebfffe7d9012"
];
return msg;
↓
[Split: One message per gateway]
↓
[Change: Set gateway ID]
Set msg.payload to msg.payload (the gateway ID)
↓
[TTS Gateway Node]
Gateway ID Source: From Message
↓
[Join: Combine all results]
Mode: automatic
After number of message parts: 3
↓
[Function: Aggregate statistics]
const gateways = msg.payload;
const total = gateways.length;
const online = gateways.filter(g => g.connected).length;
const offline = total - online;
const totalUplinks = gateways.reduce((sum, g) => sum + (g.uplink_count || 0), 0);
msg.payload = {
total: total,
online: online,
offline: offline,
onlinePercentage: ((online / total) * 100).toFixed(2),
totalUplinks: totalUplinks,
gateways: gateways
};
return msg;
↓
[Dashboard/Database/Alert]
Use Cases:
Fleet overview dashboard
Aggregate network statistics
Identify problematic gateways
Coverage analysis
4. Gateway Offline Alert System
Send notifications only when gateway goes offline (avoid spam).
Flow:
[Inject: Every 2 minutes]
↓
[TTS Gateway Node]
↓
[Function: Track status changes]
const gatewayId = msg.payload.gateway_id;
const currentStatus = msg.payload.connected;
const previousStatus = flow.get(`gateway_${gatewayId}_status`);
// Store current status
flow.set(`gateway_${gatewayId}_status`, currentStatus);
// Only continue if status changed to offline
if (previousStatus === true && currentStatus === false) {
msg.statusChanged = true;
msg.alertType = "offline";
return msg;
} else if (previousStatus === false && currentStatus === true) {
msg.statusChanged = true;
msg.alertType = "online";
return msg;
}
return null; // No change, don't send alert
↓
[Switch: Route by alert type]
↓
[Function: Format offline alert]
msg.payload = {
priority: "high",
subject: `🚨 Gateway Offline: ${msg.payload.name}`,
text: `Gateway has gone offline.
Gateway: ${msg.payload.name}
Gateway ID: ${msg.payload.gateway_id}
Location: ${msg.payload.latitude}, ${msg.payload.longitude}
Disconnected: ${msg.payload.disconnected_at}
Last uplink: ${msg.payload.last_uplink_received_at}
Please investigate immediately.`
};
return msg;
↓
[Email/SMS Alert]
[Function: Format online alert]
msg.payload = {
subject: `✅ Gateway Online: ${msg.payload.name}`,
text: `Gateway has come back online.
Gateway: ${msg.payload.name}
Connected: ${msg.payload.connected_at}
Total uplinks: ${msg.payload.uplink_count}`
};
return msg;
↓
[Email Notification]
Benefits:
No alert spam (only on status changes)
Tracks recovery automatically
Provides context in alerts
Easy to see disconnection duration
5. Gateway Health Check Report
Generate daily reports on gateway performance.
Flow:
[Inject: Daily at 8 AM]
↓
[TTS Gateway Node]
↓
[Function: Calculate 24h metrics]
const gateway = msg.payload;
const uplinks = gateway.uplink_count;
const previousUplinks = flow.get('previous_uplink_count') || uplinks;
const uplinksToday = uplinks - previousUplinks;
flow.set('previous_uplink_count', uplinks);
msg.payload = {
gateway: gateway.name,
gatewayId: gateway.gateway_id,
status: gateway.connected ? "Online ✅" : "Offline ❌",
uplinksToday: uplinksToday,
totalUplinks: uplinks,
totalDownlinks: gateway.downlink_count,
latencyMedian: gateway.round_trip_times?.median || "N/A",
lastSeen: gateway.last_uplink_received_at,
location: `${gateway.latitude}, ${gateway.longitude}`
};
return msg;
↓
[Function: Format email report]
msg.payload = {
to: "[email protected]",
subject: `Daily Gateway Health Report - ${msg.payload.gateway}`,
text: `Gateway Health Report
Gateway: ${msg.payload.gateway}
ID: ${msg.payload.gatewayId}
Status: ${msg.payload.status}
📊 Last 24 Hours:
- Uplinks received: ${msg.payload.uplinksToday}
- Median latency: ${msg.payload.latencyMedian}
- Last activity: ${msg.payload.lastSeen}
📈 Totals:
- Total uplinks: ${msg.payload.totalUplinks}
- Total downlinks: ${msg.payload.totalDownlinks}
📍 Location: ${msg.payload.location}`
};
return msg;
↓
[Email Node]
Report Contents:
Gateway status
24-hour statistics
Latency metrics
Activity timestamps
Location info
6. Coverage Analysis
Map gateway locations and coverage areas.
Flow:
[Inject: On demand]
↓
[Function: List all gateways]
msg.payload = [
"eui-gateway-1",
"eui-gateway-2",
"eui-gateway-3"
];
return msg;
↓
[Split]
↓
[TTS Gateway Node]
Gateway ID Source: From Message
↓
[Join]
↓
[Function: Extract locations]
const gateways = msg.payload;
msg.payload = gateways.map(g => ({
name: g.name,
id: g.gateway_id,
latitude: g.latitude,
longitude: g.longitude,
altitude: g.altitude,
connected: g.connected,
uplinks: g.uplink_count
}));
return msg;
↓
[Worldmap Node or Export to GeoJSON]
Use Cases:
Visualize gateway coverage
Plan gateway deployments
Identify coverage gaps
Optimize gateway placement
7. Latency Monitoring and Alerting
Monitor network latency and alert on degradation.
Flow:
[Inject: Every 5 minutes]
↓
[TTS Gateway Node]
↓
[Function: Check latency]
const rtt = msg.payload.round_trip_times;
if (!rtt) {
return null; // No RTT data
}
// Extract median latency (remove 'ms')
const latencyMs = parseInt(rtt.median);
// Define thresholds
const WARNING_THRESHOLD = 100; // ms
const CRITICAL_THRESHOLD = 200; // ms
msg.latency = latencyMs;
if (latencyMs > CRITICAL_THRESHOLD) {
msg.severity = "critical";
msg.color = "red";
} else if (latencyMs > WARNING_THRESHOLD) {
msg.severity = "warning";
msg.color = "yellow";
} else {
msg.severity = "normal";
msg.color = "green";
return null; // Don't alert on normal latency
}
return msg;
↓
[Function: Format latency alert]
msg.payload = {
subject: `${msg.severity.toUpperCase()}: High Latency Detected`,
text: `Gateway ${msg.payload.name} showing high latency:
Current median latency: ${msg.latency}ms
Min: ${msg.payload.round_trip_times.min}
Max: ${msg.payload.round_trip_times.max}
Samples: ${msg.payload.round_trip_times.count}
Severity: ${msg.severity}
Gateway: ${msg.payload.gateway_id}`
};
return msg;
↓
[Email/SMS Alert]
Thresholds:
Normal: < 100ms
Warning: 100-200ms
Critical: > 200ms
Advanced Features
Dynamic Gateway Queries
Query different gateways based on runtime conditions:
// Query gateway based on device's gateway
msg.gatewayId = msg.payload.rx_metadata[0].gateway_ids.gateway_id;
Batch Gateway Monitoring
Monitor many gateways efficiently:
// Generate list from database or API
const gateways = flow.get('gateway_list');
msg.payload = gateways.map(g => g.gateway_id);
// Use Split + TTS Gateway + Join
Historical Tracking
Store gateway metrics over time:
// Store in database
const record = {
timestamp: new Date(),
gateway_id: msg.payload.gateway_id,
connected: msg.payload.connected,
uplink_count: msg.payload.uplink_count,
median_latency: parseInt(msg.payload.round_trip_times?.median || 0)
};
// Save to InfluxDB, PostgreSQL, etc.
Best Practices
Polling Intervals
Real-time monitoring
1-2 minutes
Catch issues quickly
General monitoring
5-10 minutes
Balance freshness and API calls
Health checks
15-30 minutes
Reduce load, still responsive
Daily reports
Once per day
Sufficient for reports
Error Handling
Always implement proper error handling:
[TTS Gateway Node]
↓
[Catch Node]
↓
[Function: Handle error]
if (msg.error) {
node.warn(`Gateway query failed: ${msg.error}`);
// Check if it's an auth error
if (msg.error.includes('401')) {
node.error('API key invalid or expired');
}
// Fallback behavior
msg.payload = {
gateway_id: msg.gatewayId,
connected: false,
error: msg.error
};
}
return msg;
↓
[Dashboard with error state]
Caching
Reduce API calls by caching gateway data:
// Check cache first
const cacheKey = `gateway_${msg.gatewayId}`;
const cached = flow.get(cacheKey);
const cacheAge = flow.get(`${cacheKey}_time`);
if (cached && cacheAge && (Date.now() - cacheAge < 60000)) {
// Use cached data (less than 1 minute old)
msg.payload = cached;
return msg;
}
// Otherwise query API and cache result
// (after TTS Gateway node)
flow.set(cacheKey, msg.payload);
flow.set(`${cacheKey}_time`, Date.now());
Status Persistence
Store gateway status in context for comparison:
// Store previous status
const gatewayId = msg.payload.gateway_id;
const previousStatus = flow.get(`status_${gatewayId}`);
const currentStatus = msg.payload.connected;
// Detect status changes
if (previousStatus !== currentStatus) {
msg.statusChanged = true;
msg.previousStatus = previousStatus;
}
// Update stored status
flow.set(`status_${gatewayId}`, currentStatus);
Troubleshooting
Common Issues
"Missing configuration" error
Ensure TTS Config node is properly configured
Verify Server URL and API Key are entered
Check API Key has required permissions
"Gateway ID not configured" error
Select a gateway ID in the node configuration (Configured mode)
Or ensure
msg.payload
contains gateway ID (From Message mode)
API Error: 401 Unauthorized
API Key is invalid or expired
Generate new API Key in TTS Console
Ensure API Key has
RIGHT_GATEWAY_INFO
andRIGHT_GATEWAY_STATUS_READ
API Error: 404 Not Found
Gateway ID is incorrect or doesn't exist
Verify gateway ID format (usually
eui-...
)Check gateway exists in The Things Stack Console
Connection stats not available (null)
Gateway has never connected
Gateway is not currently active
Connection stats API returned 404 (expected for inactive gateways)
Gateway will show as
connected: false
High latency or timeouts
TTS server might be slow or overloaded
Network connectivity issues
Try increasing polling interval
Check TTS Status Page
Performance & Limitations
API Calls
Each TTS Gateway node makes 2 API calls per execution:
Gateway info (
/api/v3/gateways/{gateway_id}
)Connection stats (
/api/v3/gs/gateways/{gateway_id}/connection/stats
)
Response Times
Typical: 1-3 seconds
Slow: 3-10 seconds (server load, network latency)
Timeout: 30 seconds
Rate Limits
The Things Stack has rate limits:
Community: Varies by server region
Enterprise: Configurable per deployment
Best Practices:
Don't poll faster than 1 minute intervals
Use caching for frequently accessed data
Batch queries when monitoring multiple gateways
Monitor for 429 (Too Many Requests) errors
Integration Examples
With Datacake Nodes
Combine gateway monitoring with device monitoring:
[Inject: Every 5 minutes]
↓
[TTS Gateway Node]
↓
[Function: Check gateway status]
if (!msg.payload.connected) {
return null; // Skip if gateway offline
}
return msg;
↓
[Datacake GraphQL Semantic]
Query devices with SIGNAL semantic
↓
[Function: Analyze signal quality]
With InfluxDB
Store gateway metrics for historical analysis:
[TTS Gateway Node]
↓
[Function: Format InfluxDB point]
msg.payload = {
measurement: 'gateway_stats',
tags: {
gateway_id: msg.payload.gateway_id,
gateway_name: msg.payload.name
},
fields: {
connected: msg.payload.connected ? 1 : 0,
uplink_count: msg.payload.uplink_count || 0,
downlink_count: msg.payload.downlink_count || 0,
median_latency: parseInt(msg.payload.round_trip_times?.median || 0)
},
timestamp: new Date()
};
return msg;
↓
[InfluxDB Out Node]
With Grafana Dashboard
Query InfluxDB for visualization:
SELECT
mean("uplink_count") as "Avg Uplinks",
mean("median_latency") as "Avg Latency",
sum("connected") as "Online Gateways"
FROM "gateway_stats"
WHERE time > now() - 24h
GROUP BY time(5m), "gateway_id"
Resources
The Things Stack Documentation: thethingsindustries.com/docs
TTS API Reference: thethingsindustries.com/docs/reference/api
The Things Network Forum: thethingsnetwork.org/forum
TTS Status Page: status.thethingsnetwork.org
API Reference
Gateway Info Endpoint
GET /api/v3/gateways/{gateway_id}
Authorization: Bearer {api_key}
Returns:
Gateway identification
Configuration details
Location information
Frequency plan
Antenna details
Version information
Connection Stats Endpoint
GET /api/v3/gs/gateways/{gateway_id}/connection/stats
Authorization: Bearer {api_key}
Returns:
Connection status
Connected/disconnected timestamps
Protocol in use
Message counters
Round-trip times
Sub-band utilization
Note: Returns 404 if gateway has never connected or connection stats are unavailable.
Appendix: Gateway ID Formats
Common Formats
EUI-based:
eui-b827ebfffe8b1234
Custom ID:
my-office-gateway
With dashes:
office-gateway-01
Finding Your Gateway ID
Log in to The Things Stack Console
Navigate to Gateways
Click on your gateway
Copy the Gateway ID from the overview page
The gateway ID is shown at the top of the gateway details page and in the URL.
Last updated
Was this helpful?