2023-05-30 13:42:36 +03:00
#!/usr/bin/env python3
import subprocess
import re
import os
import json
2023-05-30 14:20:12 +03:00
import argparse
2023-05-30 13:42:36 +03:00
2023-05-30 14:20:12 +03:00
def restart_service ( history = False ) :
if history == False :
subprocess . Popen ( [ " systemctl " , " restart " , " wb-mqtt-serial " ] , stdout = subprocess . PIPE )
2023-05-30 13:42:36 +03:00
def parse_config_file ( filename ) :
with open ( filename , " r " ) as file :
config_data = json . load ( file )
device_to_port = { }
2023-05-30 14:07:49 +03:00
device_stats = { }
2023-05-30 13:42:36 +03:00
for port in config_data [ " ports " ] :
for device in port [ " devices " ] :
device_to_port [ device [ " slave_id " ] ] = port [ " path " ]
2023-05-30 14:07:49 +03:00
device_stats [ device [ " slave_id " ] ] = { " type " : device . get ( " device_type " , " Unknown type " ) , " errors " : 0 , " disconnects " : 0 , " write_failures " : 0 } # Initialize counts as zero
2023-05-30 13:42:36 +03:00
2023-05-30 14:07:49 +03:00
return device_to_port , device_stats
2023-05-30 13:42:36 +03:00
2023-05-30 14:20:12 +03:00
def parse_journal ( device_to_port , device_stats , history = False ) :
cmd = [ " journalctl " , " -f " , " -u " , " wb-mqtt-serial " ] if not history else [ " journalctl " , " -u " , " wb-mqtt-serial " ]
p = subprocess . Popen ( cmd , stdout = subprocess . PIPE )
2023-05-30 13:42:36 +03:00
last_log_line = None
for line in iter ( p . stdout . readline , b ' ' ) :
line = line . decode ( ' utf-8 ' ) # convert bytes to string
2023-05-30 14:07:49 +03:00
match_error = re . search ( r ' modbus:( \ d+): Serial protocol error: request timed out ' , line )
match_disconnect = re . search ( r ' INFO: \ [serial device \ ] device modbus:( \ d+) is disconnected ' , line )
match_write_failure = re . search ( r ' WARNING: \ [modbus \ ] failed to write: <modbus:( \ d+): ' , line )
if match_error :
device_number = match_error . group ( 1 )
device_stats [ device_number ] [ " errors " ] + = 1
elif match_disconnect :
device_number = match_disconnect . group ( 1 )
device_stats [ device_number ] [ " disconnects " ] + = 1
elif match_write_failure :
device_number = match_write_failure . group ( 1 )
device_stats [ device_number ] [ " write_failures " ] + = 1
2023-05-30 13:42:36 +03:00
last_log_line = line
# clear the console
2023-05-30 14:07:49 +03:00
os . system ( ' clear ' )
2023-05-30 13:42:36 +03:00
# print the last log line
print ( f " Last log line: { last_log_line } " )
# print error statistics
2023-05-30 14:07:49 +03:00
print_error_statistics ( device_stats , device_to_port )
2023-05-30 13:42:36 +03:00
2023-05-30 14:07:49 +03:00
def print_error_statistics ( device_stats , device_to_port ) :
print ( " \n --- Device Statistics --- " )
2023-05-30 13:42:36 +03:00
2023-05-30 14:07:49 +03:00
# sort by total count
sorted_device_stats = sorted ( device_stats . items ( ) , key = lambda x : ( x [ 1 ] [ " errors " ] , x [ 1 ] [ " disconnects " ] , x [ 1 ] [ " write_failures " ] ) , reverse = True )
2023-05-30 13:42:36 +03:00
2023-05-30 14:07:49 +03:00
max_type_length = max ( len ( stats [ ' type ' ] ) for stats in device_stats . values ( ) )
for device , stats in sorted_device_stats :
2023-05-30 13:42:36 +03:00
device_port = device_to_port . get ( device , " Unknown port " )
2023-05-30 14:07:49 +03:00
type_field = stats [ ' type ' ] . ljust ( max_type_length )
print ( f " { type_field } \t { device } \t on port: { device_port } , \t timeouts: { stats [ ' errors ' ] } , \t disconnects: { stats [ ' disconnects ' ] } , \t write failures: { stats [ ' write_failures ' ] } " )
2023-05-30 14:20:12 +03:00
def parse_args ( ) :
parser = argparse . ArgumentParser ( )
parser . add_argument ( " -H " , " --history " , help = " parse historical data from journal " , action = " store_true " )
args = parser . parse_args ( )
return args
2023-05-30 13:42:36 +03:00
if __name__ == " __main__ " :
2023-05-30 14:20:12 +03:00
args = parse_args ( )
restart_service ( history = args . history )
2023-05-30 14:07:49 +03:00
device_to_port , device_stats = parse_config_file ( " /mnt/data/etc/wb-mqtt-serial.conf " )
2023-05-30 14:20:12 +03:00
parse_journal ( device_to_port , device_stats , history = args . history )