MQTT Status based on Last Packet Received

This commit is contained in:
Skordy
2024-08-28 01:10:14 -07:00
parent 0262dd3ee5
commit 7b8c9f82e5
2 changed files with 64 additions and 41 deletions

View File

@ -604,37 +604,6 @@ client.on("connect", () => {
// handle message received // handle message received
client.on("message", async (topic, message) => { client.on("message", async (topic, message) => {
try { try {
// handle node status
if(topic.includes("/stat/!")){
try {
// get node id and status
const nodeIdHex = topic.split("/").pop();
const mqttConnectionState = message.toString();
// convert node id hex to int value
const nodeId = convertHexIdToNumericId(nodeIdHex);
// update mqtt connection state for node
await prisma.node.updateMany({
where: {
node_id: nodeId,
},
data: {
mqtt_connection_state: mqttConnectionState,
mqtt_connection_state_updated_at: new Date(),
},
});
// no need to continue with this mqtt message
return;
} catch(e) {
console.error(e);
}
}
// decode service envelope // decode service envelope
const envelope = ServiceEnvelope.decode(message); const envelope = ServiceEnvelope.decode(message);
if(!envelope.packet){ if(!envelope.packet){
@ -661,6 +630,16 @@ client.on("message", async (topic, message) => {
} }
} }
// Update Node MQTT status based on Last Packet Received time
const ret = await prisma.node.updateMany({
where: {
node_id: convertHexIdToNumericId(envelope.gatewayId),
},
data: {
mqtt_connection_state_updated_at: new Date(),
},
});
// attempt to decrypt encrypted packets // attempt to decrypt encrypted packets
const isEncrypted = envelope.packet.encrypted?.length > 0; const isEncrypted = envelope.packet.encrypted?.length > 0;
if(isEncrypted){ if(isEncrypted){

View File

@ -1485,6 +1485,30 @@
</select> </select>
</div> </div>
<!-- configNodesDisconnectedAgeInSeconds -->
<div class="p-2">
<label class="block text-sm font-medium text-gray-900">Nodes Disconnected Age</label>
<div class="text-xs text-gray-600 mb-2">Nodes that have not uploaded to MQTT in this time will show as blue icons. Reload to update map.</div>
<select v-model="configNodesDisconnectedAgeInSeconds" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
<option :value="null">Don't show as offline</option>
<option value="900">15 minutes</option>
<option value="1800">30 minutes</option>
<option value="2700">45 minutes</option>
<option value="3600">1 hour</option>
<option value="7200">2 hours</option>
<option value="10800">3 hours</option>
<option value="21600">6 hours</option>
<option value="43200">12 hours</option>
<option value="86400">24 hours</option>
<option value="172800">2 days</option>
<option value="259200">3 days</option>
<option value="345600">4 days</option>
<option value="432000">5 days</option>
<option value="518400">6 days</option>
<option value="604800">7 days</option>
</select>
</div>
<!-- configNodesOfflineAgeInSeconds --> <!-- configNodesOfflineAgeInSeconds -->
<div class="p-2"> <div class="p-2">
<label class="block text-sm font-medium text-gray-900">Nodes Offline Age</label> <label class="block text-sm font-medium text-gray-900">Nodes Offline Age</label>
@ -1777,6 +1801,19 @@
} }
} }
function getConfigNodesDisconnectedAgeInSeconds() {
const value = localStorage.getItem("config_nodes_disconnected_age_in_seconds");
return value != null ? parseInt(value) : null;
}
function setConfigNodesDisconnectedAgeInSeconds(value) {
if(value != null){
return localStorage.setItem("config_nodes_disconnected_age_in_seconds", value);
} else {
return localStorage.removeItem("config_nodes_disconnected_age_in_seconds");
}
}
function getConfigNodesOfflineAgeInSeconds() { function getConfigNodesOfflineAgeInSeconds() {
const value = localStorage.getItem("config_nodes_offline_age_in_seconds"); const value = localStorage.getItem("config_nodes_offline_age_in_seconds");
return value != null ? parseInt(value) : null; return value != null ? parseInt(value) : null;
@ -1836,6 +1873,7 @@
isShowingAnnouncement: this.shouldShowAnnouncement(), isShowingAnnouncement: this.shouldShowAnnouncement(),
configNodesMaxAgeInSeconds: window.getConfigNodesMaxAgeInSeconds(), configNodesMaxAgeInSeconds: window.getConfigNodesMaxAgeInSeconds(),
configNodesDisconnectedAgeInSeconds: window.getConfigNodesDisconnectedAgeInSeconds(),
configNodesOfflineAgeInSeconds: window.getConfigNodesOfflineAgeInSeconds(), configNodesOfflineAgeInSeconds: window.getConfigNodesOfflineAgeInSeconds(),
configWaypointsMaxAgeInSeconds: window.getConfigWaypointsMaxAgeInSeconds(), configWaypointsMaxAgeInSeconds: window.getConfigWaypointsMaxAgeInSeconds(),
configNeighboursMaxDistanceInMeters: window.getConfigNeighboursMaxDistanceInMeters(), configNeighboursMaxDistanceInMeters: window.getConfigNeighboursMaxDistanceInMeters(),
@ -2791,6 +2829,9 @@
configNodesMaxAgeInSeconds() { configNodesMaxAgeInSeconds() {
window.setConfigNodesMaxAgeInSeconds(this.configNodesMaxAgeInSeconds); window.setConfigNodesMaxAgeInSeconds(this.configNodesMaxAgeInSeconds);
}, },
configNodesDisconnectedAgeInSeconds() {
window.setConfigNodesDisconnectedAgeInSeconds(this.configNodesDisconnectedAgeInSeconds);
},
configNodesOfflineAgeInSeconds() { configNodesOfflineAgeInSeconds() {
window.setConfigNodesOfflineAgeInSeconds(this.configNodesOfflineAgeInSeconds); window.setConfigNodesOfflineAgeInSeconds(this.configNodesOfflineAgeInSeconds);
}, },
@ -3500,12 +3541,15 @@
// icon based on mqtt connection state // icon based on mqtt connection state
var icon = iconMqttDisconnected; var icon = iconMqttDisconnected;
if(node.mqtt_connection_state === "online"){ const now = moment();
icon = iconMqttConnected; const configNodesDisconnectedAgeInSeconds = getConfigNodesDisconnectedAgeInSeconds();
if(configNodesDisconnectedAgeInSeconds){
if(now.diff(moment(node.mqtt_connection_state_updated_at)) > configNodesDisconnectedAgeInSeconds * 1000){
icon = iconMqttConnected;
}
} }
// use offline icon for nodes older than configured node offline age // use offline icon for nodes older than configured node offline age
const now = moment();
const configNodesOfflineAgeInSeconds = getConfigNodesOfflineAgeInSeconds(); const configNodesOfflineAgeInSeconds = getConfigNodesOfflineAgeInSeconds();
if(configNodesOfflineAgeInSeconds){ if(configNodesOfflineAgeInSeconds){
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at)); const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
@ -3519,7 +3563,7 @@
icon: icon, icon: icon,
tagName: node.node_id, tagName: node.node_id,
// we want to show online nodes above offline, but without needing to use separate layer groups // we want to show online nodes above offline, but without needing to use separate layer groups
zIndexOffset: node.mqtt_connection_state === "online" ? 1000 : -1000, zIndexOffset: now.diff(moment(node.mqtt_connection_state_updated_at)) > configNodesDisconnectedAgeInSeconds * 1000 ? 1000 : -1000,
}).on('click', function(event) { }).on('click', function(event) {
// close tooltip on click to prevent tooltip and popup showing at same time // close tooltip on click to prevent tooltip and popup showing at same time
event.target.closeTooltip(); event.target.closeTooltip();
@ -3937,13 +3981,13 @@
// human friendly connection state // human friendly connection state
var mqttStatus = ""; var mqttStatus = "";
var mqttStatusLastUpdated = node.mqtt_connection_state_updated_at ? `(${moment(new Date(node.mqtt_connection_state_updated_at)).fromNow()})` : ""; var mqttStatusLastUpdated = node.mqtt_connection_state_updated_at ? `${moment(new Date(node.mqtt_connection_state_updated_at)).fromNow()}` : "";
if(node.mqtt_connection_state === "online"){ if(moment().diff(moment(node.mqtt_connection_state_updated_at)) > getConfigNodesDisconnectedAgeInSeconds() * 1000){
mqttStatus = `<span class="text-green-700">Connected</span> ${mqttStatusLastUpdated}`; mqttStatus = `<span class="text-green-700">Heard</span> ${mqttStatusLastUpdated}`;
} else if(node.mqtt_connection_state === "offline"){ } else if(moment().diff(moment(node.mqtt_connection_state_updated_at)) < getConfigNodesDisconnectedAgeInSeconds() * 1000){
mqttStatus = `<span class="text-blue-700">Disconnected</span> ${mqttStatusLastUpdated}`; mqttStatus = `<span class="text-blue-700">Last Heard</span> ${mqttStatusLastUpdated}`;
} else { } else {
mqttStatus = `<span class="text-blue-700">Disconnected</span>`; mqttStatus = `<span class="text-blue-700">Not heard</span>`;
} }
var loraFrequencyRange = getRegionFrequencyRange(node.region_name); var loraFrequencyRange = getRegionFrequencyRange(node.region_name);