diff --git a/etc/report_generator.py b/etc/report_generator.py index 0981638..f0c9687 100644 --- a/etc/report_generator.py +++ b/etc/report_generator.py @@ -190,19 +190,15 @@ def parse_log_file(file_path): log_data['gps_coordinates'][node_id].append((float(lat), float(lon))) # get telemetry data - # example, | System: int1:2.5.2.771cb52, Nodes:2, Telemetry: ChUse/Tx 0.0%/0.0% Uptime:10d Volt:4.3 - telemetry_match = re.search(r'System: int(\d+):(\d+\.\d+\.\d+\.\w+), Nodes:(\d+), Telemetry: ChUse/Tx (\d+\.\d+)%/(\d+\.\d+)% Uptime:(\d+d) Volt:(\d+\.\d+)', line) + # example line = | Telemetry:1 numPacketsTx:0 numPacketsRx:0 numPacketsTxErr:0 numPacketsRxErr:0 ChUtil%:0.0 AirTx%:0.0 Rx#:0 Tx#:0 Nodes:2 Uptime:10d Volt:4.3 Firmware:2.5.2.771cb52 + telemetry_match = re.search(r'Telemetry:(\d+) numPacketsTx:(\d+) numPacketsRx:(\d+) numPacketsTxErr:(\d+) numPacketsRxErr:(\d+) ChUtil%:(\d+\.\d) AirTx%:(\d+\.\d) Rx#:(\d+) Tx#:(\d+) Nodes:(\d+) Uptime:(\d+\w) Volt:(\d+\.\d) Firmware:(\d+\.\d+\.\d+\.\w+)', line) if telemetry_match: - interface_number, firmware_version, nodes, chUse, tx, uptime, voltage = telemetry_match.groups() - data = f"Nodes {nodes}, Uptime{uptime}, ChUse {chUse}%, Tx {tx}%, Voltage {voltage}" + interface_number, numPacketsTx, numPacketsRx, numPacketsTxErr, numPacketsRxErr, ChUtil, AirTx, Rx, Tx, nodes, uptime, volt, firmware_version = telemetry_match.groups() + data = f"Tx: {numPacketsTx}, Rx: {numPacketsRx}, TxErr: {numPacketsTxErr}, RxErr: {numPacketsRxErr}, ChUtil: {ChUtil}, AirTx: {AirTx}, Rx#: {Rx}, Tx#: {Tx}, Nodes: {nodes}, Uptime: {uptime}, Volt: {volt}" if interface_number == '1': log_data['firmware1_version'] = firmware_version log_data['node1_uptime'] = data #log_data['nodeCount1'] = nodes - elif interface_number == '2': - log_data['firmware2_version'] = firmware_version - log_data['node2_uptime'] = data - #log_data['nodeCount2'] = nodes # get name and nodeID for devices if 'Autoresponder Started for Device' in line: diff --git a/etc/report_generator5.py b/etc/report_generator5.py index 7d8f0c7..009f4c3 100644 --- a/etc/report_generator5.py +++ b/etc/report_generator5.py @@ -199,20 +199,15 @@ def parse_log_file(file_path): log_data['gps_coordinates'][node_id].append((float(lat), float(lon))) # get telemetry data - # example, System: int1:2.5.2.771cb52, Nodes:2, Telemetry: ChUse/Tx 0.0%/0.0% Uptime:10d Volt:4.311 - telemetry_match = re.search(r'System: int(\d+):(\d+\.\d+\.\d+\.\w+), Nodes:(\d+), Telemetry: ChUse/Tx (\d+\.\d+)%/(\d+\.\d+)% Uptime:(\d+d).{1} Volt:(\d+\.\d+)', line) + # example line = | Telemetry:1 numPacketsTx:0 numPacketsRx:0 numPacketsTxErr:0 numPacketsRxErr:0 ChUtil%:0.0 AirTx%:0.0 Rx#:0 Tx#:0 Nodes:2 Uptime:10d Volt:4.3 Firmware:2.5.2.771cb52 + telemetry_match = re.search(r'Telemetry:(\d+) numPacketsTx:(\d+) numPacketsRx:(\d+) numPacketsTxErr:(\d+) numPacketsRxErr:(\d+) ChUtil%:(\d+\.\d) AirTx%:(\d+\.\d) Rx#:(\d+) Tx#:(\d+) Nodes:(\d+) Uptime:(\d+\w) Volt:(\d+\.\d) Firmware:(\d+\.\d+\.\d+\.\w+)', line) if telemetry_match: - interface_number, firmware_version, nodes, chUse, tx, uptime, voltage = telemetry_match.groups() - data = f"Nodes {nodes}, Uptime{uptime}, ChUse {chUse}%, Tx {tx}%, Voltage {voltage}" - print(f"Interface {interface_number} Firmware {firmware_version} {data}") + interface_number, numPacketsTx, numPacketsRx, numPacketsTxErr, numPacketsRxErr, ChUtil, AirTx, Rx, Tx, nodes, uptime, volt, firmware_version = telemetry_match.groups() + data = f"Tx: {numPacketsTx}, Rx: {numPacketsRx}, TxErr: {numPacketsTxErr}, RxErr: {numPacketsRxErr}, ChUtil: {ChUtil}, AirTx: {AirTx}, Rx#: {Rx}, Tx#: {Tx}, Nodes: {nodes}, Uptime: {uptime}, Volt: {volt}" if interface_number == '1': log_data['firmware1_version'] = firmware_version log_data['node1_uptime'] = data #log_data['nodeCount1'] = nodes - elif interface_number == '2': - log_data['firmware2_version'] = firmware_version - log_data['node2_uptime'] = data - #log_data['nodeCount2'] = nodes # get name and nodeID for devices if 'Autoresponder Started for Device' in line: diff --git a/mesh_bot.py b/mesh_bot.py index ce7edd6..c268372 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -942,6 +942,29 @@ def onReceive(packet, interface): elif interface2_enabled and interface2_type == 'ble': rxNode = 2 + # TELEMETRY + if packet.get('decoded') and packet['decoded']['portnum'] == 'TELEMETRY_APP': + #print(f"Telemetry Packet: {packet}") + # get the telemetry data + telemetry = packet['decoded']['telemetry'] + if telemetry.get('deviceMetrics'): + deviceMetrics = telemetry['deviceMetrics'] + #print(f"deviceMetrics: {deviceMetrics}") + if telemetry.get('localStats'): + localStats = telemetry['localStats'] + if localStats.get('numPacketsTx') and localStats.get('numPacketsRx'): + global numPacketsTx, numPacketsRx, numPacketsTxErr, numPacketsRxErr + # Assign the values and include rxNode + numPacketsTx = (localStats['numPacketsTx'], rxNode) + numPacketsRx = (localStats['numPacketsRx'], rxNode) + try: + numPacketsTxErr = (localStats['numPacketsTxErr'], rxNode) + numPacketsRxErr = (localStats['numPacketsRxErr'], rxNode) + except KeyError: + numPacketsTxErr = (0, rxNode) + numPacketsRxErr = (0, rxNode) + #airUtilTx = (round(localStats['airUtilTx'], 2), rxNode) + # check for BBS DM for mail delivery if bbs_enabled and 'decoded' in packet: message_from_id = packet['from'] diff --git a/modules/system.py b/modules/system.py index 8bf2253..3cdf05f 100644 --- a/modules/system.py +++ b/modules/system.py @@ -16,6 +16,8 @@ help_message = "CMD?:" asyncLoop = asyncio.new_event_loop() games_enabled = False multiPingList = [{'message_from_id': 0, 'count': 0, 'type': '', 'deviceID': 0}] +lastTelemetryRequest = 0 +numPacketsTx, numPacketsRx, numPacketsTxErr, numPacketsRxErr = 0, 0, 0, 0 # Ping Configuration if ping_enabled: @@ -667,25 +669,55 @@ def getNodeFirmware(nodeID=0, nodeInt=1): return fwVer def getNodeTelemetry(nodeID=0, nodeInt=1): - dataResponse = "" + # throttle the telemetry requests to prevent spamming the device + global lastTelemetryRequest, numPacketsTx, numPacketsRx, numPacketsTxErr, numPacketsRxErr + if time.time() - lastTelemetryRequest < 600: + return -1 + lastTelemetryRequest = time.time() # get the telemetry data for a node + dataResponse = "" if nodeInt == 1: chutil = round(interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("channelUtilization", 0), 1) airUtilTx = round(interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("airUtilTx", 0), 1) uptimeSeconds = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("uptimeSeconds", 0) batteryLevel = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("batteryLevel", 0) voltage = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("voltage", 0) + #numPacketsRx = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("localStats", {}).get("numPacketsRx", 0) + #numPacketsTx = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("localStats", {}).get("numPacketsTx", 0) + numTotalNodes = len(interface1.nodes) elif nodeInt == 2: chutil = round(interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("channelUtilization", 0), 1) airUtilTx = round(interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("airUtilTx", 0), 1) uptimeSeconds = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("uptimeSeconds", 0) batteryLevel = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("batteryLevel", 0) voltage = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("voltage", 0) + #numPacketsRx = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("localStats", {}).get("numPacketsRx", 0) + #numPacketsTx = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("localStats", {}).get("numPacketsTx", 0) + numTotalNodes = len(interface2.nodes) else: return -1 + # packet telemetry + if nodeInt == 1: + dataResponse += f"Telemetry:{nodeInt} numPacketsTx:{numPacketsTx} numPacketsRx:{numPacketsRx} numPacketsTxErr:{numPacketsTxErr} numPacketsRxErr:{numPacketsRxErr}" + if nodeInt == 2: + dataResponse += f"Telemetry:{nodeInt} numPacketsTx:{numPacketsTx2} numPacketsRx:{numPacketsRx2} numPacketsTxErr:{numPacketsTxErr2} numPacketsRxErr:{numPacketsRxErr2}" + + # Channel utilization and airUtilTx - dataResponse += " ChUse/Tx " + str(chutil) + "%" + "/" + str(airUtilTx) + "%" + " " + dataResponse += " ChUtil%:" + str(round(chutil, 2)) + " AirTx%:" + str(round(airUtilTx, 2)) + + if chutil > 40: + logger.warning(f"System: High Channel Utilization {chutil}% on Device: {nodeInt}") + + if airUtilTx > 25: + logger.warning(f"System: High Air Utilization {airUtilTx}% on Device: {nodeInt}") + + # add packet Rx/Tx info to the response + dataResponse += f" Rx#:{numPacketsRx} Tx#:{numPacketsTx}" + + # Number of nodes + dataResponse += " Nodes:" + str(numTotalNodes) # Uptime uptimeSeconds = getPrettyTime(uptimeSeconds) @@ -693,11 +725,13 @@ def getNodeTelemetry(nodeID=0, nodeInt=1): # add battery info to the response emji = "🔌" if batteryLevel == 101 else "đŸĒĢ" if batteryLevel < 10 else "🔋" - if batteryLevel == 101: - dataResponse += f" Volt:{round(voltage, 1)}" - else: - dataResponse += f" {emji}{batteryLevel}% Volt:{round(voltage, 1)}" - + dataResponse += f" Volt:{round(voltage, 1)}" + + if batteryLevel < 25: + logger.warning(f"System: Low Battery Level: {batteryLevel}{emji} on Device: {nodeInt}") + elif batteryLevel < 10: + logger.critical(f"System: Critical Battery Level: {batteryLevel}{emji} on Device: {nodeInt}") + return dataResponse def handleMultiPing(nodeID=0, deviceID=1): @@ -892,10 +926,9 @@ async def watchdog(): handleMultiPing(0,1) # Telemetry data - tmp = int1Data - int1Data = f"int1:{firmware}, Nodes:{len(interface1.nodes)}, Telemetry:{getNodeTelemetry(0, 1)}" - if tmp[:-4] != int1Data[:-4]: - logger.debug(f"System: {int1Data}") + int1Data = getNodeTelemetry(0, 1) +f" Firmware:{firmware}" + if int1Data != -1: + logger.debug(int1Data) if retry_int1: try: @@ -920,11 +953,10 @@ async def watchdog(): # multiPing handler handleMultiPing(0,2) - # Telemetry data - tmp = int2Data[:-4] - int2Data = f"int2:{firmware2}, Nodes:{len(interface2.nodes)}, Telemetry:{getNodeTelemetry(0, 2)}" - if tmp[:-4] != int2Data[:-4]: - logger.debug(f"System: {int2Data}") + # Telemetry data + int2Data = getNodeTelemetry(0, 2) + f" Firmware:{firmware2}" + if int1Data != -1: + logger.debug(int2Data) if retry_int2: try: