def run_main():
    logger.info("... Starting Raspberry Pi Power Monitor")
    logger.info("Press Ctrl-c to quit...")
    # The following empty dictionaries will hold the respective calculated values at the end of each polling cycle, which are then averaged prior to storing the value to the DB.
    solar_power_values = dict(power=[], pf=[], current=[])
    home_load_values = dict(power=[], pf=[], current=[])
    net_power_values = dict(power=[], current=[])
    ct0_dict = dict(power=[], pf=[], current=[])
    ct1_dict = dict(power=[], pf=[], current=[])
    ct2_dict = dict(power=[], pf=[], current=[])
    ct3_dict = dict(power=[], pf=[], current=[])
    ct4_dict = dict(power=[], pf=[], current=[])
    ct5_dict = dict(power=[], pf=[], current=[])
    rms_voltages = []
    i = 0  # Counter for aggregate function

    while True:
        try:
            board_voltage = get_board_voltage()
            samples = collect_data(2000)
            poll_time = samples['time']
            ct0_samples = samples['ct0']
            ct1_samples = samples['ct1']
            ct2_samples = samples['ct2']
            ct3_samples = samples['ct3']
            ct4_samples = samples['ct4']
            ct5_samples = samples['ct5']
            v_samples = samples['voltage']
            rebuilt_waves = rebuild_waves(samples, ct0_phasecal, ct1_phasecal,
                                          ct2_phasecal, ct3_phasecal,
                                          ct4_phasecal, ct5_phasecal)
            results = calculate_power(rebuilt_waves, board_voltage)

            # # RMS calculation for phase correction only - this is not needed after everything is tuned. The following code is used to compare the RMS power to the calculated real power.
            # # Ideally, you want the RMS power to equal the real power when you are measuring a purely resistive load.
            # rms_power_0 = round(results['ct0']['current'] * results['ct0']['voltage'], 2)  # AKA apparent power
            # rms_power_1 = round(results['ct1']['current'] * results['ct1']['voltage'], 2)  # AKA apparent power
            # rms_power_2 = round(results['ct2']['current'] * results['ct2']['voltage'], 2)  # AKA apparent power
            # rms_power_3 = round(results['ct3']['current'] * results['ct3']['voltage'], 2)  # AKA apparent power
            # rms_power_4 = round(results['ct4']['current'] * results['ct4']['voltage'], 2)  # AKA apparent power
            # rms_power_5 = round(results['ct5']['current'] * results['ct5']['voltage'], 2)  # AKA apparent power

            # Prepare values for database storage
            grid_0_power = results['ct0']['power']  # CT0 Real Power
            grid_1_power = results['ct1']['power']  # CT1 Real Power
            grid_2_power = results['ct2']['power']  # CT2 Real Power
            grid_3_power = results['ct3']['power']  # CT3 Real Power
            grid_4_power = results['ct4']['power']  # CT4 Real Power
            grid_5_power = results['ct5']['power']  # CT5 Real Power

            grid_0_current = results['ct0']['current']  # CT0 Current
            grid_1_current = results['ct1']['current']  # CT1 Current
            grid_2_current = results['ct2']['current']  # CT2 Current
            grid_3_current = results['ct3']['current']  # CT3 Current
            grid_4_current = results['ct4']['current']  # CT4 Current
            grid_5_current = results['ct5']['current']  # CT5 Current

            # If you are monitoring solar/generator inputs to your panel, specify which CT number(s) you are using, and uncomment the commented lines.
            solar_power = 0
            solar_current = 0
            solar_pf = 0
            # solar_power = results['ct3']['power']
            # solar_current = results['ct3']['current']
            # solar_pf = results['ct3']['pf']
            voltage = results['voltage']

            # Set solar power and current to zero if the solar power is under 20W.
            if solar_power < 20:
                solar_power = 0
                solar_current = 0
                solar_pf = 0

            # Determine if the system is net producing or net consuming right now by looking at the two panel mains.
            # Since the current measured is always positive, we need to add a negative sign to the amperage value if we're exporting power.
            if grid_0_power < 0:
                grid_0_current = grid_0_current * -1
            if grid_1_power < 0:
                grid_1_current = grid_1_current * -1
            if solar_power > 0:
                solar_current = solar_current * -1

            # Unless your specific panel setup matches mine exactly, the following four lines will likely need to be re-written:
            home_consumption_power = grid_0_power + grid_1_power + grid_2_power + grid_3_power + grid_4_power + grid_5_power + solar_power
            net_power = home_consumption_power - solar_power
            home_consumption_current = grid_0_current + grid_1_current + grid_2_current + grid_3_current + grid_4_current + grid_5_current - solar_current
            net_current = grid_0_current + grid_1_current + grid_2_current + grid_3_current + grid_4_current + grid_5_current + solar_current

            if net_power < 0:
                current_status = "Producing"
            else:
                current_status = "Consuming"

            # Average 2 readings before sending to db
            if i < 2:
                solar_power_values['power'].append(solar_power)
                solar_power_values['current'].append(solar_current)
                solar_power_values['pf'].append(solar_pf)

                home_load_values['power'].append(home_consumption_power)
                home_load_values['current'].append(home_consumption_current)
                net_power_values['power'].append(net_power)
                net_power_values['current'].append(net_current)

                ct0_dict['power'].append(results['ct0']['power'])
                ct0_dict['current'].append(results['ct0']['current'])
                ct0_dict['pf'].append(results['ct0']['pf'])
                ct1_dict['power'].append(results['ct1']['power'])
                ct1_dict['current'].append(results['ct1']['current'])
                ct1_dict['pf'].append(results['ct1']['pf'])
                ct2_dict['power'].append(results['ct2']['power'])
                ct2_dict['current'].append(results['ct2']['current'])
                ct2_dict['pf'].append(results['ct2']['pf'])
                ct3_dict['power'].append(results['ct3']['power'])
                ct3_dict['current'].append(results['ct3']['current'])
                ct3_dict['pf'].append(results['ct3']['pf'])
                ct4_dict['power'].append(results['ct4']['power'])
                ct4_dict['current'].append(results['ct4']['current'])
                ct4_dict['pf'].append(results['ct4']['pf'])
                ct5_dict['power'].append(results['ct5']['power'])
                ct5_dict['current'].append(results['ct5']['current'])
                ct5_dict['pf'].append(results['ct5']['pf'])
                rms_voltages.append(voltage)
                i += 1

            else:  # Calculate the average, send the result to InfluxDB, and reset the dictionaries for the next 2 sets of data.
                infl.write_to_influx(
                    solar_power_values,
                    home_load_values,
                    net_power_values,
                    ct0_dict,
                    ct1_dict,
                    ct2_dict,
                    ct3_dict,
                    ct4_dict,
                    ct5_dict,
                    poll_time,
                    i,
                    rms_voltages,
                )
                solar_power_values = dict(power=[], pf=[], current=[])
                home_load_values = dict(power=[], pf=[], current=[])
                net_power_values = dict(power=[], current=[])
                ct0_dict = dict(power=[], pf=[], current=[])
                ct1_dict = dict(power=[], pf=[], current=[])
                ct2_dict = dict(power=[], pf=[], current=[])
                ct3_dict = dict(power=[], pf=[], current=[])
                ct4_dict = dict(power=[], pf=[], current=[])
                ct5_dict = dict(power=[], pf=[], current=[])
                rms_voltages = []
                i = 0

                if logger.handlers[0].level == 10:
                    t = PrettyTable(
                        ['', 'CT0', 'CT1', 'CT2', 'CT3', 'CT4', 'CT5'])
                    t.add_row([
                        'Watts',
                        round(results['ct0']['power'], 3),
                        round(results['ct1']['power'], 3),
                        round(results['ct2']['power'], 3),
                        round(results['ct3']['power'], 3),
                        round(results['ct4']['power'], 3),
                        round(results['ct5']['power'], 3)
                    ])
                    t.add_row([
                        'Current',
                        round(results['ct0']['current'], 3),
                        round(results['ct1']['current'], 3),
                        round(results['ct2']['current'], 3),
                        round(results['ct3']['current'], 3),
                        round(results['ct4']['current'], 3),
                        round(results['ct5']['current'], 3)
                    ])
                    t.add_row([
                        'P.F.',
                        round(results['ct0']['pf'], 3),
                        round(results['ct1']['pf'], 3),
                        round(results['ct2']['pf'], 3),
                        round(results['ct3']['pf'], 3),
                        round(results['ct4']['pf'], 3),
                        round(results['ct5']['pf'], 3)
                    ])
                    t.add_row([
                        'Voltage',
                        round(results['voltage'], 3), '', '', '', '', ''
                    ])
                    s = t.get_string()
                    logger.debug('\n' + s)

            #sleep(0.1)

        except KeyboardInterrupt:
            infl.close_db()
            sys.exit()
def run_main():
    logger.info("Press Ctrl-c to quit...")
    # The following empty dictionaries will hold the respective calculated values at the end of each polling cycle, which are then averaged prior to storing the value to the DB.
    solar_power_values = dict(power=[], pf=[], current=[])
    home_load_values = dict(power=[], pf=[], current=[])
    net_power_values = dict(power=[], current=[])
    ct0_dict = dict(power=[], pf=[], current=[])
    ct1_dict = dict(power=[], pf=[], current=[])
    ct2_dict = dict(power=[], pf=[], current=[])
    ct3_dict = dict(power=[], pf=[], current=[])
    ct4_dict = dict(power=[], pf=[], current=[])
    ct5_dict = dict(power=[], pf=[], current=[])
    rms_voltage_values = []
    i = 0  # Counter for aggregate function

    while True:
        try:
            board_voltage = get_board_voltage()
            samples = collect_data(2000)
            poll_time = samples['time']
            ct0_samples = samples['ct0']
            ct1_samples = samples['ct1']
            ct2_samples = samples['ct2']
            ct3_samples = samples['ct3']
            ct4_samples = samples['ct4']
            ct5_samples = samples['ct5']
            v_samples = samples['voltage']
            rebuilt_waves = rebuild_waves(samples, ct0_phasecal, ct1_phasecal,
                                          ct2_phasecal, ct3_phasecal,
                                          ct4_phasecal, ct5_phasecal)
            results = calculate_power(rebuilt_waves, board_voltage)

            # # RMS calculation for phase correction only - this is not needed after everything is tuned. The following code is used to compare the RMS power to the calculated real power.
            # # Ideally, you want the RMS power to equal the real power when you are measuring a purely resistive load.
            # rms_power_0 = round(results['ct0']['current'] * results['ct0']['voltage'], 2)  # AKA apparent power
            # rms_power_1 = round(results['ct1']['current'] * results['ct1']['voltage'], 2)  # AKA apparent power
            # rms_power_2 = round(results['ct2']['current'] * results['ct2']['voltage'], 2)  # AKA apparent power
            # rms_power_3 = round(results['ct3']['current'] * results['ct3']['voltage'], 2)  # AKA apparent power
            # rms_power_4 = round(results['ct4']['current'] * results['ct4']['voltage'], 2)  # AKA apparent power
            # rms_power_5 = round(results['ct5']['current'] * results['ct5']['voltage'], 2)  # AKA apparent power
            # phase_corrected_power_0 = results['ct0']['power']
            # phase_corrected_power_1 = results['ct1']['power']
            # phase_corrected_power_2 = results['ct2']['power']
            # phase_corrected_power_3 = results['ct3']['power']
            # phase_corrected_power_4 = results['ct4']['power']
            # phase_corrected_power_5 = results['ct5']['power']

            # # diff is the difference between the real_power (phase corrected) compared to the simple rms power calculation.
            # # This is used to calibrate for the "unknown" phase error in each CT.  The phasecal value for each CT input should be adjusted so that diff comes as close to zero as possible.
            # diff_0 = phase_corrected_power_0 - rms_power_0
            # diff_1 = phase_corrected_power_1 - rms_power_1
            # diff_2 = phase_corrected_power_2 - rms_power_2
            # diff_3 = phase_corrected_power_3 - rms_power_3
            # diff_4 = phase_corrected_power_4 - rms_power_4
            # diff_5 = phase_corrected_power_5 - rms_power_5

            # Phase Corrected Results
            # logger.debug("\n")
            # logger.debug(f"CT0 Real Power: {round(results['ct0']['power'], 2):>10} W | Amps: {round(results['ct0']['current'], 2):<7} | RMS Power: {round(results['ct0']['current'] * results['ct0']['voltage'], 2):<6} W | PF: {round(results['ct0']['pf'], 5)}")
            # logger.debug(f"CT1 Real Power: {round(results['ct1']['power'], 2):>10} W | Amps: {round(results['ct1']['current'], 2):<7} | RMS Power: {round(results['ct1']['current'] * results['ct1']['voltage'], 2):<6} W | PF: {round(results['ct1']['pf'], 5)}")
            # logger.debug(f"CT2 Real Power: {round(results['ct2']['power'], 2):>10} W | Amps: {round(results['ct2']['current'], 2):<7} | RMS Power: {round(results['ct2']['current'] * results['ct2']['voltage'], 2):<6} W | PF: {round(results['ct2']['pf'], 5)}")
            # logger.debug(f"CT3 Real Power: {round(results['ct3']['power'], 2):>10} W | Amps: {round(results['ct3']['current'], 2):<7} | RMS Power: {round(results['ct3']['current'] * results['ct3']['voltage'], 2):<6} W | PF: {round(results['ct3']['pf'], 5)}")
            # logger.debug(f"CT4 Real Power: {round(results['ct4']['power'], 2):>10} W | Amps: {round(results['ct4']['current'], 2):<7} | RMS Power: {round(results['ct4']['current'] * results['ct4']['voltage'], 2):<6} W | PF: {round(results['ct4']['pf'], 5)}")
            # logger.debug(f"CT5 Real Power: {round(results['ct5']['power'], 2):>10} W | Amps: {round(results['ct5']['current'], 2):<7} | RMS Power: {round(results['ct5']['current'] * results['ct5']['voltage'], 2):<6} W | PF: {round(results['ct5']['pf'], 5)}")
            # logger.debug(f"Line Voltage: {round(results['voltage'], 2)} V")

            # Prepare values for database storage
            grid_0_power = results['ct0']['power']  # 200A Main (left)
            grid_1_power = results['ct1']['power']  # 200A Main (right)
            grid_2_power = results['ct2']['power']  # 100A Main (top)
            grid_4_power = results['ct4']['power']  # 100A Main (bottom)
            grid_5_power = results['ct5']['power']  # Unused

            grid_0_current = results['ct0']['current']
            grid_1_current = results['ct1']['current']
            grid_2_current = results['ct2']['current']
            grid_4_current = results['ct4']['current']
            grid_5_current = results['ct5']['current']

            solar_power = results['ct3']['power']
            solar_current = results['ct3']['current']
            solar_pf = results['ct3']['pf']

            # Set solar power and current to zero if the solar power is under 20W.
            if solar_power < 20:
                solar_power = 0
                solar_current = 0
                solar_pf = 0

            # Determine if the system is net producing or net consuming right now by looking at the two panel mains.
            # Since the current measured is always positive, we need to add a negative sign to the amperage value if we're exporting power.
            if grid_0_power < 0:
                grid_0_current = grid_0_current * -1
            if grid_1_power < 0:
                grid_1_current = grid_1_current * -1
            if solar_power > 0:
                solar_current = solar_current * -1

            # Unless your specific panel setup matches mine exactly, the following four lines will likely need to be re-written:
            home_consumption_power = grid_2_power + grid_4_power + grid_0_power + grid_1_power + solar_power
            net_power = home_consumption_power - solar_power
            home_consumption_current = grid_2_current + grid_4_current + grid_0_current + grid_1_current - solar_current
            net_current = grid_0_current + grid_1_current + grid_2_current + grid_4_current + solar_current

            if net_power < 0:
                current_status = "Producing"
            else:
                current_status = "Consuming"

            # Average 2 readings before sending to db
            if i < 2:
                solar_power_values['power'].append(solar_power)
                solar_power_values['current'].append(solar_current)
                solar_power_values['pf'].append(solar_pf)

                home_load_values['power'].append(home_consumption_power)
                home_load_values['current'].append(home_consumption_current)
                net_power_values['power'].append(net_power)
                net_power_values['current'].append(net_current)

                ct0_dict['power'].append(results['ct0']['power'])
                ct0_dict['current'].append(results['ct0']['current'])
                ct0_dict['pf'].append(results['ct0']['pf'])
                ct1_dict['power'].append(results['ct1']['power'])
                ct1_dict['current'].append(results['ct1']['current'])
                ct1_dict['pf'].append(results['ct1']['pf'])
                ct2_dict['power'].append(results['ct2']['power'])
                ct2_dict['current'].append(results['ct2']['current'])
                ct2_dict['pf'].append(results['ct2']['pf'])
                ct3_dict['power'].append(results['ct3']['power'])
                ct3_dict['current'].append(results['ct3']['current'])
                ct3_dict['pf'].append(results['ct3']['pf'])
                ct4_dict['power'].append(results['ct4']['power'])
                ct4_dict['current'].append(results['ct4']['current'])
                ct4_dict['pf'].append(results['ct4']['pf'])
                ct5_dict['power'].append(results['ct5']['power'])
                ct5_dict['current'].append(results['ct5']['current'])
                ct5_dict['pf'].append(results['ct5']['pf'])
                i += 1

            else:  # Calculate the average, send the result to InfluxDB, and reset the dictionaries for the next 2 sets of data.
                infl.write_to_influx(solar_power_values, home_load_values,
                                     net_power_values, ct0_dict, ct1_dict,
                                     ct2_dict, ct3_dict, ct4_dict, ct5_dict,
                                     poll_time, i)
                solar_power_values = dict(power=[], pf=[], current=[])
                home_load_values = dict(power=[], pf=[], current=[])
                net_power_values = dict(power=[], current=[])
                ct0_dict = dict(power=[], pf=[], current=[])
                ct1_dict = dict(power=[], pf=[], current=[])
                ct2_dict = dict(power=[], pf=[], current=[])
                ct3_dict = dict(power=[], pf=[], current=[])
                ct4_dict = dict(power=[], pf=[], current=[])
                ct5_dict = dict(power=[], pf=[], current=[])
                i = 0

                if logger.handlers[0].level == 10:
                    t = PrettyTable(
                        ['', 'CT0', 'CT1', 'CT2', 'CT3', 'CT4', 'CT5'])
                    t.add_row([
                        'Watts',
                        round(results['ct0']['power'], 3),
                        round(results['ct1']['power'], 3),
                        round(results['ct2']['power'], 3),
                        round(results['ct3']['power'], 3),
                        round(results['ct4']['power'], 3),
                        round(results['ct5']['power'], 3)
                    ])
                    t.add_row([
                        'Current',
                        round(results['ct0']['current'], 3),
                        round(results['ct1']['current'], 3),
                        round(results['ct2']['current'], 3),
                        round(results['ct3']['current'], 3),
                        round(results['ct4']['current'], 3),
                        round(results['ct5']['current'], 3)
                    ])
                    t.add_row([
                        'P.F.',
                        round(results['ct0']['pf'], 3),
                        round(results['ct1']['pf'], 3),
                        round(results['ct2']['pf'], 3),
                        round(results['ct3']['pf'], 3),
                        round(results['ct4']['pf'], 3),
                        round(results['ct5']['pf'], 3)
                    ])
                    t.add_row([
                        'Voltage',
                        round(results['voltage'], 3), '', '', '', '', ''
                    ])
                    s = t.get_string()
                    logger.debug('\n' + s)

            #sleep(0.1)

        except KeyboardInterrupt:
            infl.close_db()
            sys.exit()