diff --git a/bms.py b/bms.py index f125152..d601563 100755 --- a/bms.py +++ b/bms.py @@ -3,11 +3,11 @@ # Communicate with a JBD/SZLLT BMS and return basic information # in order to shutdown equipment when voltage levels drop or remaining # capacity gets low -# TODO: get individual cell voltage # TODO: scripts to shutdown NAS when voltage goes below 13.xV or # percent_capacity goes below 25% # import argparse +import atexit import json import pprint import serial @@ -20,9 +20,17 @@ try: can_export_prometheus = True except: can_export_prometheus = False +try: + from influxdb_client import InfluxDBClient, Point + from influxdb_client.client.write_api import SYNCHRONOUS + import datetime + can_export_influxdb = True + influxclient = None + writeapi = None +except: + can_export_influxdb = False - -PROMETHEUS_UPDATE_PERIOD = 30 +DAEMON_UPDATE_PERIOD = 30 SERIALPORT = "/dev/ttyUSB0" #SERIALPORT = "/dev/rfcomm1" BAUDRATE = 9600 @@ -53,7 +61,10 @@ ser.stopbits = serial.STOPBITS_ONE # number of stop bits ser.timeout = 1 # timeout block read ser.writeTimeout = 1 # timeout for write -def cleanup(ser, debug): +''' Clean up serial port ''' +def cleanup(): + global debug + global ser if debug > 2: print("Cleaning up...") if ser.is_open: @@ -61,6 +72,16 @@ def cleanup(ser, debug): ser.reset_output_buffer() # flush output buffer, aborting current output ser.close() +''' Close remote connections ''' +def shutdown(): + global debug + global influxclient + if influxclient is not None: + if writeapi is not None: + writeapi.close() + influxclient.close() + + def calculate_checksum(msg): checksum = '' return checksum @@ -98,7 +119,9 @@ def bytes_to_date(high, low): return "{:04d}-{:02d}-{:02d}".format(year, mon, day) # takes a serial object and a message, returns a response -def requestMessage(ser, reqmsg, debug): +def requestMessage(reqmsg): + global ser + global debug if debug > 2: print('Starting Up Serial Monitor') if ser.is_open: @@ -130,7 +153,7 @@ def requestMessage(ser, reqmsg, debug): while ser.in_waiting == 0: # Return an empty string if we end up waiting too long if wait_time > 2: - cleanup(ser, debug) + cleanup() return '' if debug > 2: print("Waiting for data...") @@ -144,7 +167,7 @@ def requestMessage(ser, reqmsg, debug): return '' if debug > 0: print("Read data: {0}".format(response.hex())) - cleanup(ser, debug) + cleanup() return response except Exception as e: print("error communicating...: {0}".function(str(e))) @@ -152,6 +175,7 @@ def requestMessage(ser, reqmsg, debug): print("cannot open serial port") def parse_03_response(response): + global debug data = dict() # Response is 34 bytes: # 00 begin: \xDD @@ -193,9 +217,9 @@ def parse_03_response(response): vtot = bytes_to_digits(response[4], response[5]) * 0.01 data['bms_voltage_total_volts'] = dict() data['bms_voltage_total_volts']['help'] = "Total Voltage" + data['bms_voltage_total_volts']['raw_value'] = vtot data['bms_voltage_total_volts']['value'] = "{:.2f}".format(vtot) data['bms_voltage_total_volts']['units'] = "V" - #data["Total Voltage"] = "{:.2f}V".format(vtot) if debug > 1: print("Total voltage: {:.2f}V".format(vtot)) @@ -203,9 +227,9 @@ def parse_03_response(response): current = convert_to_signed(current) * 0.01 data["bms_current_amps"] = dict() data["bms_current_amps"]['help'] = "Current" + data["bms_current_amps"]['raw_value'] = current data["bms_current_amps"]['value'] = "{:.2f}".format(current) data["bms_current_amps"]['units'] = "A" - #data["Current"] = "{:.2f}A".format(current) if debug > 1: print("Current: {:.2f}A".format(current)) @@ -213,14 +237,14 @@ def parse_03_response(response): nom_cap = bytes_to_digits(response[10], response[11]) * 0.01 data['bms_capacity_remaining_ah'] = dict() data['bms_capacity_remaining_ah']['help'] = "Remaining Capacity" + data['bms_capacity_remaining_ah']['raw_value'] = res_cap data['bms_capacity_remaining_ah']['value'] = "{:.2f}".format(res_cap) data['bms_capacity_remaining_ah']['units'] = "Ah" data['bms_capacity_nominal_ah'] = dict() data['bms_capacity_nominal_ah']['help'] = "Nominal Capacity" + data['bms_capacity_nominal_ah']['raw_value'] = nom_cap data['bms_capacity_nominal_ah']['value'] = "{:.2f}".format(nom_cap) data['bms_capacity_nominal_ah']['units'] = "Ah" - #data["Remaining Capacity"] = "{:.2f}Ah".format(res_cap) - #data["Nominal Capacity"] = "{:.2f}Ah".format(nom_cap) if debug > 1: print("Remaining capacity: {:.2f}Ah".format(res_cap)) print("Nominal capacity: {:.2f}Ah".format(nom_cap)) @@ -228,8 +252,8 @@ def parse_03_response(response): cycle_times = bytes_to_digits(response[12], response[13]) data['bms_charge_cycles'] = dict() data['bms_charge_cycles']['help'] = "Charge Cycles" + data['bms_charge_cycles']['raw_value'] = cycle_times data['bms_charge_cycles']['value'] = "{0}".format(cycle_times) - #data["Charge Cycles"] = "{0}".format(cycle_times) if debug > 1: print("Cycle times: {0}".format(cycle_times)) @@ -237,15 +261,14 @@ def parse_03_response(response): data['bms_manufacture_date'] = dict() data['bms_manufacture_date']['help'] = "Date of Manufacture" data['bms_manufacture_date']['info'] = "{0}".format(man_date) - #data["Date of Manufacture"] = "{0}".format(man_date) if debug > 1: print("Manufacturing date: {0}".format(man_date)) cells = response[25] # 4S data['bms_cell_number'] = dict() data['bms_cell_number']['help'] = "Cells" + data['bms_cell_number']['raw_value'] = cells data['bms_cell_number']['value'] = "{0}".format(cells) - #data["Cells"] = "{0}".format(cells) if debug > 1: print("Cells: {0}S".format(cells)) @@ -272,6 +295,7 @@ def parse_03_response(response): data['bms_cells_balancing'] = dict() data['bms_cells_balancing']['help'] = "Cells balancing" data['bms_cells_balancing']['label'] = 'cell' + data['bms_cells_balancing']['raw_values'] = dict() data['bms_cells_balancing']['values'] = dict() for cell in range(cells): # Cells from 1 to 16 are recorded in balance_state_low, @@ -284,13 +308,13 @@ def parse_03_response(response): state = balance_state_low hilo_cell = cell # Cells are recorded as groups of 4 bits (0x0-0xF) per 4 cells - g = int(hilo_cell / 4) + g = int(hilo_cell / 4) b = 2**(hilo_cell - (g * 4 )) + data['bms_cells_balancing']['raw_values'][cell+1] = int(bool((state >> g) & b)) data['bms_cells_balancing']['values'][cell+1] = "{0}".format(int(bool((state >> g) & b))) - #data["Balancing"][cell+1] = "{0}".format(bool((state >> g) & b)) if debug > 1: print("Balancing cell {0}: {1}".format(cell, bool((state >> g & b)))) - + protection_state = bytes_to_digits(response[20], response[21]) sop = protection_state & 1 sup = protection_state & 2 @@ -307,56 +331,56 @@ def parse_03_response(response): slm = protection_state & 4096 data['bms_protection_sop_bool'] = dict() data['bms_protection_sop_bool']['help'] = "Single overvoltage protection" - data['bms_protection_sop_bool']['value'] ="{0}".format(int(bool(sop))) + data['bms_protection_sop_bool']['raw_value'] = int(bool(sop)) + data['bms_protection_sop_bool']['value'] = "{0}".format(int(bool(sop))) data['bms_protection_sup_bool'] = dict() data['bms_protection_sup_bool']['help'] = "Single undervoltage protection" - data['bms_protection_sup_bool']['value'] ="{0}".format(int(bool(sup))) + data['bms_protection_sup_bool']['raw_value'] = int(bool(sup)) + data['bms_protection_sup_bool']['value'] = "{0}".format(int(bool(sup))) data['bms_protection_wgop_bool'] = dict() data['bms_protection_wgop_bool']['help'] = "Whole group overvoltage protection" - data['bms_protection_wgop_bool']['value'] ="{0}".format(int(bool(gop))) + data['bms_protection_wgop_bool']['raw_value'] = int(bool(gop)) + data['bms_protection_wgop_bool']['value'] = "{0}".format(int(bool(gop))) data['bms_protection_wgup_bool'] = dict() data['bms_protection_wgup_bool']['help'] = "Whole group undervoltage protection" - data['bms_protection_wgup_bool']['value'] ="{0}".format(int(bool(gup))) + data['bms_protection_wgup_bool']['raw_value'] = int(bool(gup)) + data['bms_protection_wgup_bool']['value'] = int(bool(gup)) data['bms_protection_cotp_bool'] = dict() data['bms_protection_cotp_bool']['help'] = "Charging over-temperature protection" - data['bms_protection_cotp_bool']['value'] ="{0}".format(int(bool(cotp))) + data['bms_protection_cotp_bool']['raw_value'] = \ + data['bms_protection_cotp_bool']['value'] = "{0}".format(int(bool(cotp))) data['bms_protection_cutp_bool'] = dict() data['bms_protection_cutp_bool']['help'] = "Charging under-temperature protection" - data['bms_protection_cutp_bool']['value'] ="{0}".format(int(bool(cutp))) + data['bms_protection_cutp_bool']['raw_value'] = int(bool(cutp)) + data['bms_protection_cutp_bool']['value'] = "{0}".format(int(bool(cutp))) data['bms_protection_dotp_bool'] = dict() data['bms_protection_dotp_bool']['help'] = "Discharging over-temperature protection" - data['bms_protection_dotp_bool']['value'] ="{0}".format(int(bool(dotp))) + data['bms_protection_dotp_bool']['raw_value'] = int(bool(dotp)) + data['bms_protection_dotp_bool']['value'] = "{0}".format(int(bool(dotp))) data['bms_protection_dutp_bool'] = dict() data['bms_protection_dutp_bool']['help'] = "Discharging under-protection" - data['bms_protection_dutp_bool']['value'] ="{0}".format(int(bool(dutp))) + data['bms_protection_dutp_bool']['raw_value'] = int(bool(dutp)) + data['bms_protection_dutp_bool']['value'] = "{0}".format(int(bool(dutp))) data['bms_protection_cocp_bool'] = dict() data['bms_protection_cocp_bool']['help'] = "Charging over-current protection" - data['bms_protection_cocp_bool']['value'] ="{0}".format(int(bool(cocp))) + data['bms_protection_cocp_bool']['raw_value'] = int(bool(cocp)) + data['bms_protection_cocp_bool']['value'] = "{0}".format(int(bool(cocp))) data['bms_protection_docp_bool'] = dict() data['bms_protection_docp_bool']['help'] = "Discharging over-current protection" - data['bms_protection_docp_bool']['value'] ="{0}".format(int(bool(docp))) + data['bms_protection_docp_bool']['raw_value'] = int(bool(docp)) + data['bms_protection_docp_bool']['value'] = "{0}".format(int(bool(docp))) data['bms_protection_scp_bool'] = dict() data['bms_protection_scp_bool']['help'] = "Short-circuit protection" - data['bms_protection_scp_bool']['value'] ="{0}".format(int(bool(scp))) + data['bms_protection_scp_bool']['raw_value'] = int(bool(scp)) + data['bms_protection_scp_bool']['value'] = "{0}".format(int(bool(scp))) data['bms_protection_fdic_bool'] = dict() data['bms_protection_fdic_bool']['help'] = "Front detection IC error" - data['bms_protection_fdic_bool']['value'] ="{0}".format(int(bool(fdic))) + data['bms_protection_fdic_bool']['raw_value'] = int(bool(fdic)) + data['bms_protection_fdic_bool']['value'] = "{0}".format(int(bool(fdic))) data['bms_protection_slmos_bool'] = dict() data['bms_protection_slmos_bool']['help'] = "Software lock MOS" - data['bms_protection_slmos_bool']['value'] ="{0}".format(int(bool(slm))) - #data["Single overvoltage protection"] = "{0}".format(bool(sop)) - #data["Single undervoltage protection"] = "{0}".format(bool(sup)) - #data["Whole group overvoltage protection"] = "{0}".format(bool(gop)) - #data["Whole group undervoltage protection"] = "{0}".format(bool(gup)) - #data["Charging over-temperature protection"] = "{0}".format(bool(cotp)) - #data["Charging under-temperature protection"] = "{0}".format(bool(cutp)) - #data["Discharging over-temperature protection"] = "{0}".format(bool(dotp)) - #data["Discharging under-protection"] = "{0}".format(bool(dutp)) - #data["Charging over-current protection"] = "{0}".format(bool(cocp)) - #data["Discharging over-current protection"] = "{0}".format(bool(docp)) - #data["Short-circuit protection"] = "{0}".format(bool(scp)) - #data["Front detection IC error"] = "{0}".format(bool(fdic)) - #data["Software lock MOS"] = "{0}".format(bool(slm)) + data['bms_protection_slmos_bool']['raw_value'] = int(bool(slm)) + data['bms_protection_slmos_bool']['value'] = int(bool(slm)) if debug > 2: print("Protection state: {0}".format(protection_state)) print("Single overvoltage protection: {0}".format(bool(sop))) @@ -379,9 +403,9 @@ def parse_03_response(response): rsoc = response[23] * 0.01 data['bms_capacity_charge_ratio'] = dict() data['bms_capacity_charge_ratio']['help'] = "Percent Charge" + data['bms_capacity_charge_ratio']['raw_value'] = format(rsoc) data['bms_capacity_charge_ratio']['value'] = "{0}".format(rsoc) data['bms_capacity_charge_ratio']['units'] = "\u2030" - #data["Percent Charge"] = "{0}".format(rsoc) if debug > 1: print("Capacity remaining: {0}%".format(rsoc * 100)) @@ -389,12 +413,12 @@ def parse_03_response(response): control_status = response[24] data['bms_charge_is_charging'] = dict() data['bms_charge_is_charging']['help'] = "MOSFET charging" + data['bms_charge_is_charging']['raw_value'] = int(bool(control_status & 1)) data['bms_charge_is_charging']['value'] = int(bool(control_status & 1)) data['bms_charge_is_discharging'] = dict() data['bms_charge_is_discharging']['help'] = "MOSFET discharging" - data['bms_charge_is_discharging']['value'] = int(bool(control_status & 1)) - #data["Charging"] = bool(control_status & 1) - #data["Discharging"] = bool((control_status >> 1) & 1) + data['bms_charge_is_discharging']['raw_value'] = int(bool(control_status & 1)) + data['bms_charge_is_discharging']['value'] = "{0}".format(int(bool(control_status & 1))) if debug > 1: if (control_status & 1): print("MOSFET charging: yes") @@ -412,17 +436,17 @@ def parse_03_response(response): temperatures.append((bytes_to_digits(response[27+(2*i)], response[28+(2*i)]) - 2731) * 0.1) data['bms_temperature_sensor_num'] = dict() data['bms_temperature_sensor_num']['help'] = "Temperature Sensors" - data['bms_temperature_sensor_num']['value'] = ntc_num - #data["Temperature Sensors"] = ntc_num - #data["Temperature"] = dict() + data['bms_temperature_sensor_num']['raw_value'] = ntc_num + data['bms_temperature_sensor_num']['value'] = "{0}".format(ntc_num) data['bms_temperature_celcius'] = dict() data['bms_temperature_celcius']['help'] = "Temperature" data['bms_temperature_celcius']['units'] = "\u00B0C" data['bms_temperature_celcius']['label'] = 'sensor' + data['bms_temperature_celcius']['raw_values'] = dict() data['bms_temperature_celcius']['values'] = dict() for i, temp in enumerate(temperatures): + data['bms_temperature_celcius']['raw_values'][i+1] = temp data['bms_temperature_celcius']['values'][i+1] = "{:.2f}".format(temp) - #data["Temperature"][i+1] = "{:.2f}\u00B0C".format(temp) if debug > 1: print("Number of temperature sensors: {0}".format(ntc_num)) for i, temp in enumerate(temperatures): @@ -469,23 +493,24 @@ def parse_04_response(response): return False if data_len > 0: - #data["Cell Voltages"] = dict() data['bms_voltage_cells_volts'] = dict() data['bms_voltage_cells_volts']['help'] = "Cell Voltages" data['bms_voltage_cells_volts']['units'] = "V" data['bms_voltage_cells_volts']['label'] = "cell" + data['bms_voltage_cells_volts']['raw_values'] = dict() data['bms_voltage_cells_volts']['values'] = dict() for cell in range(int(data_len / 2)): first = (cell * 2) + 4 second = (cell * 2) + 5 cellv = bytes_to_digits(response[first], response[second]) * 0.001 + data['bms_voltage_cells_volts']['raw_values'][cell+1] = cellv data['bms_voltage_cells_volts']['values'][cell+1] = "{:.3f}".format(cellv) - #data["Cell Voltages"][i+1] = "{:.3f}V".format(cellv) if debug > 1: print("Cell {:.0f}: {:.3f}V".format(cell+1, cellv)) return data -def collect_data(ser, debug): +def collect_data(): + global debug # Request is 7 bytes: # \xDD for start # \xA5 for read, \x5A for write @@ -493,7 +518,7 @@ def collect_data(ser, debug): # \x77 ends data = dict() reqmsg = bytearray([ 0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77 ]) - response_03 = requestMessage(ser, reqmsg, debug) + response_03 = requestMessage(reqmsg) if len(response_03) == 0: if debug > 0: @@ -502,7 +527,7 @@ def collect_data(ser, debug): response_03 = bytearray(response_03) reqmsg = bytearray([ 0xDD, 0xA5, 0x04, 0x00, 0xFF, 0xFC, 0x77 ]) - response_04 = requestMessage(ser, reqmsg, debug) + response_04 = requestMessage(reqmsg) if len(response_04) == 0: if debug > 0: @@ -525,10 +550,11 @@ def collect_data(ser, debug): return data -def main(ser, debug): +def main(): + global debug data = dict() while bool(data) is False: - data = collect_data(ser, debug) + data = collect_data() time.sleep(1) if args.report_json: @@ -539,14 +565,15 @@ def main(ser, debug): pp.pprint(data) -def prometheus_export(ser, debug, daemonize=True, filename=False): +def prometheus_export(daemonize=True, filename=False): + global debug if not can_export_prometheus: return data = dict() # Initialize data structure, to fill in help values while bool(data) is False: - data = collect_data(ser, debug) + data = collect_data() time.sleep(1) registry = prometheus_client.CollectorRegistry(auto_describe=True) @@ -560,21 +587,21 @@ def prometheus_export(ser, debug, daemonize=True, filename=False): while True: # Delay, collect new data, and start again - time.sleep(PROMETHEUS_UPDATE_PERIOD) + time.sleep(DAEMON_UPDATE_PERIOD) # Reset data, so it is re-populated correctly data = dict() while bool(data) is False: - data = collect_data(ser, debug) + data = collect_data() time.sleep(1) prometheus_populate_metric(metric, data) prometheus_client.generate_latest(registry) else: if not filename: print("Invalid filename supplied"); - return False + return False prometheus_client.write_to_textfile(filename, registry=registry) return True - + def prometheus_create_metric(registry, data): metric = dict() for name, contains in data.items(): @@ -613,30 +640,156 @@ def prometheus_populate_metric(metric, data): pass +def influxdb_export(bucket, url=None, org=None, token=None, daemonize=True): + global debug + global influxclient + + if not can_export_influxdb: + return + + data = dict() + # Initialize data structure, to fill in help values + while bool(data) is False: + data = collect_data() + time.sleep(1) + + if url: + influxclient = InfluxDBClient(url=url, token=token, org=org) + else: + influxclient = InfluxDBClient.from_env_properties() + influxdb_write_snapshot(bucket, data) + + if (daemonize): + while True: + # Delay, collect new data, and start again + time.sleep(DAEMON_UPDATE_PERIOD) + # Reset data, so it is re-populated correctly + data = dict() + while bool(data) is False: + data = collect_data() + time.sleep(1) + influxdb_write_snapshot(bucket, data) + influxclient.close() + return + +def influxdb_write_snapshot(bucket,data): + global debug + global influxclient + global writeapi + writeapi = influxclient.write_api(write_options=SYNCHRONOUS) + # Populate the data structure this period + points = influxdb_create_snapshot(data) + writeapi.write(bucket=bucket, record=points) + writeapi.close() + return + +def influxdb_create_snapshot(data): + global debug + points = [] + helpmsg = '' + units = '' + now = datetime.datetime.now(datetime.timezone.utc).isoformat() + ''' Note that the fieldname is set to "gauge" in order to retain + compatibility with data imported from Prometheus (and it's + as good a name as any). ''' + for kind, contains in data.items(): + if contains.get('help'): + helpmsg = contains.get('help') + if contains.get('units'): + units = contains.get('units') + # Simple values + if contains.get('raw_value') is not None: + value = contains.get('raw_value') + if debug > 2: + print("value: {} : {}".format(kind, value)); + point = Point(kind) \ + .tag("units", units) \ + .tag("help", helpmsg) \ + .field("gauge", value) \ + .time(now) + points.append(point) + # Doesn't have a value, but multiple values, each with a label: + if contains.get('raw_values') is not None and isinstance(contains.get('raw_values'), dict): + label = contains.get('label') + for idx, label_value in contains.get('raw_values').items(): + if debug > 2: + print("labels: {} [{}] : {}".format(kind, idx, label_value)); + point = Point(kind) \ + .tag(label, idx) \ + .tag("units", units) \ + .tag("help", helpmsg) \ + .field("gauge", label_value) \ + .time(now) + points.append(point) + # Information (like a manufacturing date or a serial number) + if contains.get('info') is not None: + value = contains.get('info') + if debug > 2: + print("info: {} : {}".format(kind, value)); + point = Point(kind) \ + .tag("units", units) \ + .tag("help", helpmsg) \ + .field("gauge", value) \ + .time(now) + points.append(point) + else: + pass + return points + + + if __name__ == '__main__': + debug = 0 + atexit.register(cleanup) + atexit.register(shutdown) try: parser = argparse.ArgumentParser( - description='Query JBD BMS and report status', + description='Query JBD BMS and report status', add_help=True, ) - parser.add_argument('--json', '-j', dest='report_json', action='store_true', + parser.add_argument('--json', '-j', dest='report_json', action='store_true', default=False, help='Report data as JSON') parser.add_argument('--prometheus', '-p', dest='report_prometheus', action='store_true', default=False, help='Daemonize and report data to Prometheus') - parser.add_argument('--textfile', '-t', dest='report_textfile', type=str, action='store', + parser.add_argument('--file', '-f', dest='report_textfile', type=str, action='store', default=False, help='Report data to Prometheus using textfile ') + parser.add_argument('--influxdb', '-i', dest='report_influxdb', action='store_true', + default=False, help='Daemonize and report data to InfluxDB using INFLUXDB_V2_URL, INFLUXDB_V2_ORG and INFLUXDB_V2_TOKEN environment variables') + parser.add_argument('--bucket', '-b', dest='influx_bucket', type=str, action='store', + default="ups", help='Set the bucket name when sending data to influxdb (defaults to "ups")') + parser.add_argument('--url', '-u', dest='influx_url', type=str, action='store', + default=False, help='Set the URL when sending data to influxdb (overrides INFLUXDB environment variables)') + parser.add_argument('--org', '-o', dest='influx_org', type=str, action='store', + default=False, help='Set the influx organization when sending data to influxdb (overrides INFLUXDB environment variables)') + parser.add_argument('--token', '-t', dest='influx_token', type=str, action='store', + default=False, help='Set the influx token when sending data to influxdb (overrides INFLUXDB environment variables)') parser.add_argument('--print', dest='report_print', action='store_true', default=True, help='Report data as text') parser.add_argument('--verbose', '-v', action='count', default=0, help='Print more verbose information (can be specified multiple times)') args = parser.parse_args() + debug=args.verbose + if args.report_influxdb: + num_args = 0 + for arg in [ args.influx_url, args.influx_org, args.influx_token ]: + if arg is not False: + num_args += 1 + if num_args != 0 and num_args != 3: + raise argparse.ArgumentTypeError('Missing value for --url, --org or --token') + if args.report_prometheus: - prometheus_export(ser, debug, daemonize=True) + prometheus_export(daemonize=True) + if args.report_influxdb: + influxdb_export(bucket=args.influx_bucket, \ + url=args.influx_url, \ + org=args.influx_org, \ + token=args.influx_token, \ + daemonize=True) elif args.report_textfile: - prometheus_export(ser, debug, daemonize=False, filename=args.report_textfile) + prometheus_export(daemonize=False, filename=args.report_textfile) else: - main(ser, debug) + main() except KeyboardInterrupt: - cleanup(ser, debug) + cleanup()