class Plug():
    def __init__(self, plug_ip):
        # Init plug
        self.plug = SmartPlug(plug_ip)

    # --

    def info(self):
        print(' -- Plug Info -- ')
        print('Name:      %s' % self.plug.name)
        print('Model:     %s' % self.plug.model)
        print('Mac:       %s' % self.plug.mac)
        print('Time:      %s' % self.plug.time)

        print('Is on:     %s' % self.plug.is_on)
        print('Nightmode: %s' % (not self.plug.led))
        print('RSSI:      %s' % self.plug.rssi)

    # --

    def plug_on(self):
        time.sleep(1)
        if not self.plug.is_on:
            self.plug.turn_on()
            print('Plug turned on')

    # --

    def plug_off(self):
        time.sleep(1)
        if self.plug.is_on:
            self.plug.turn_off()
            print('Plug turned off')
def main_loop():
    # init
    inv = Inverter(0x1, '/dev/ttyUSB0')
    inv.version()
    if OWMKey:
        owm = Weather(OWMKey, OWMLat, OWMLon)
        owm.fresh = False
    else:
        owm = False

    pvo = PVOutputAPI(APIKEY, SYSTEMID)
    fan = SmartPlug(FAN_IP_ADDR)

    # Loop until end of universe
    while True:
        if owm:
            try:
                owm.get()
                owm.fresh = True
            except Exception as e:
                print('Error getting weather: {}'.format(e))
                owm.fresh = False

            # get readings from inverter, if success send  to pvoutput
        inv.read_inputs()
        if inv.status != -1:
            if inv.temp >= 30:
                fan.turn_on()
            else:
                fan.turn_off()

            temp = owm.temperature if owm and owm.fresh else None

            pvo.send_status(date=inv.date,
                            energy_gen=inv.wh_today,
                            power_gen=inv.ac_power,
                            vdc=inv.pv_volts,
                            vac=inv.ac_volts,
                            temp=temp,
                            temp_inv=inv.temp,
                            energy_life=inv.wh_total,
                            power_vdc=inv.pv_power)
            # sleep until next multiple of 5 minutes
            min = 5 - localnow().minute % 5
            sleep(min * 60 - localnow().second)
        else:
            # some error
            sleep(60)  # 1 minute before try again
Exemple #3
0
def main(panel_ip='192.168.1.161/meters.xml',
         socket_ip='192.168.1.61',
         threshold=0.7,
         interval=30,
         single_shot=False,
         max_tries=None,
         log_file='C:\\Users\\eugen\\plugger\\log.csv',
         test_plug=False,
         daily_log_dir='C:\\Users\\eugen\\plugger\\daily_logs\\',
         timed_log_when='midnight',
         timed_log_interval=None,
         days_to_log=28):
    """
    Do iterations over a loop which tests the power output at panel_ip,
    and manages the state of a plug at socket_ip, according to the threshold
    power output level.

    If pass single_shot=True, will do one test and exit, after making
    max_tries number of attempts to make a successful read and switch

    Otherwise will operate continuously. Interrupt with ctrl-c

    To test:
        pass socket_ip=None and test_plug=True to simulate the plug
        pass a test xml page on localserver as panel_ip, eg:
            <line1>x</line1>
            <OutputPower>99</OutputPower>
            <line3>x</line3>
        .. and serve the page the project folder with:
            $ python -m http.server
        (can edit and save this file on the fly to simulate panel output)

    """

    # make a daily logging directory if doesn't exist
    if not os.path.exists(daily_log_dir):
        os.mkdir(daily_log_dir)

    # set up logging
    formatter = logging.Formatter('%(asctime)-15s %(msg)-10s')
    # formatter.datefmt = ('%d/%m/%y %H:%M:%S')
    file_path = os.path.join(daily_log_dir, 'log')
    print('made a folder for logs: {file_path}')

    if timed_log_interval is None:
        handler = TimedRotatingFileHandler(file_path,
                                           when=timed_log_when,
                                           backupCount=days_to_log)

    else:
        handler = TimedRotatingFileHandler(file_path,
                                           when=timed_log_when,
                                           interval=timed_log_interval,
                                           backupCount=days_to_log)

    handler.setLevel(logging.INFO)
    handler.setFormatter(formatter)

    log = logging.getLogger()
    log.setLevel(logging.INFO)
    log.addHandler(handler)

    # initial entry
    log.info('')
    log.info('*' * 50)
    log.info('')
    if single_shot:
        log.info('[main 0.01] Calling main, mode=single')
    else:
        log.info('[main 0.02] Calling main, mode=cont')

    # create a plug instance
    if socket_ip is not None:
        try:
            plug = SmartPlug(socket_ip)
            log.info('[main 0.05] initial plug found')

        except:
            print('Could not find a plug at', socket_ip)
            log.info('[main 0.10] initial plug NOT FOUND')
            return 1

    elif test_plug:
        plug = TestPlug()
        log.info('[main 0.20] using test plug')

    else:
        print('need either a socket_ip or pass test_plug=True')
        log.info('[main 0.30] exiting as no plug')
        return 1

    interval_by_min = f'{str(interval // 60)} min, {str(interval % 60)} sec'

    splash_width = 60
    info = plug.info
    print('')
    print('*' * 12, 'PLUGGER ENERGY MANAGEMENT SYSTEM', '*' * 12)
    print('')
    print('version'.ljust(pads[0]), '0.1')
    print('')
    print('Plug IP address:'.ljust(pads[0]), socket_ip)
    print('Plug name'.ljust(pads[0]), info['alias'])
    print('Plug model'.ljust(pads[0]), info['model'])
    print('Initial plug state:'.ljust(pads[0]), "ON" if plug.is_on else "OFF")
    print('')
    print('Panel IP address:'.ljust(pads[0]), panel_ip)
    print('Panel power output threshold:'.ljust(pads[0]), threshold)
    print('')
    print('Test interval:'.ljust(pads[0]), interval_by_min)
    print('Testing mode:'.ljust(pads[0]),
          'single shot' if single_shot else 'continuous')
    print('Max attempts (if single shot):'.ljust(pads[0]),
          max_tries if single_shot else 'n/a')
    print('')
    print('*' * 59)
    print('')

    time.sleep(1)

    # initialise the log file if reqd
    if not os.path.exists(log_file):
        with open(log_file, 'a', newline="") as f:
            writer = csv.writer(f, delimiter=",")
            writer.writerow(CSV_COLUMNS)

    tries = 0

    # main loop
    while True:
        log.info('[main 0.40] entering main loop')

        ts = time.strftime('%d/%m/%y %H:%M:%S')
        log_list = [ts, 'single' if single_shot else 'cont']

        if single_shot:
            print(ts, f'[{tries + 1}/{max_tries}]'.ljust(7), end=" ")
        else:
            print(ts, end=" ")

        # try to read the panel's current output
        log.info('[main 0.50] ready to read panel')
        success, panel_output = get_panel_output(panel_ip=panel_ip,
                                                 target='OutputPower',
                                                 log=log)
        log.info(f'[main 0.60] panel read: success={success}')
        log.info(f'[main 0.60] panel read: output={panel_output}')

        if not success:
            print(f'failed to get panel output, error: {panel_output}')
            if single_shot:
                tries += 1
                if tries == max_tries:
                    log.info('[main 0.70] reached max tries, exiting')
                    return 0
            time.sleep(interval)
            continue

        log_list.extend([success, panel_output])
        print('panel reading: ' + str(panel_output).ljust(pads[1]), end=' ')

        try:
            socket_state = plug.is_on
            log.info(f'[main 0.80] read plug state: {socket_state}')
        except:
            print('cannot find plug')
            log.info(f'[main 0.90] cannot read plug')
            if single_shot:
                tries += 1
                if tries == max_tries:
                    log.info('[main 1.00] reached max tries, exiting')
                    return 0
            time.sleep(interval)
            continue

        log_list.append(socket_state)

        if panel_output >= threshold:
            if socket_state:
                log_list.append('leave on')
                log.info(f'[main 1.10] output over threshold, leaving on')
                print('leave on')

            else:
                try:
                    plug.turn_on()
                    log.info(f'[main 1.20] *** turned plug ON ***')
                except:
                    print('cannot turn on plug')
                    log.info(f'[main 1.30] cannot turn on plug')
                    if single_shot:
                        tries += 1
                        if tries == max_tries:
                            log.info('[main 1.40] reached max tries, exiting')
                            return 0
                    time.sleep(interval)
                    continue
                print('** TURN ON **')
                log_list.append('activate')

        elif panel_output < threshold:
            if socket_state:
                try:
                    plug.turn_off()
                    log.info(f'[main 1.50] *** turned plug OFF ***')
                except:
                    print('cannot find plug')
                    log.info(f'[main 1.60] cannot turn off plug')
                    if single_shot:
                        tries += 1
                        if tries == max_tries:
                            log.info('[main 1.70] reached max tries, exiting')
                            return 0
                    time.sleep(interval)
                    continue
                print('** TURN OFF **')
                log_list.append('deactivate')

            else:
                log_list.append('leave off')
                print('leave off')

        # log a plug reading after any changes
        try:
            socket_state = plug.is_on
            log.info(
                f'[main 1.80] got plug reading after changes: {socket_state}')
        except:
            print('cannot find plug')
            log.info(f'[main 1.90] cannot read plug after changes')
            socket_state = 'not found after changes'
            continue

        log_list.append(socket_state)

        # write out log
        with open(log_file, 'a', newline="") as f:
            writer = csv.writer(f, delimiter=",")
            writer.writerow(log_list)

        # exit loop if only a single shot required
        if single_shot:
            return 0

        log.info(f'[main 2.00] reached end of main loop')
        time.sleep(interval)
import sys
sys.path.append('../')

from tplink_smartplug import SmartPlug

plug = SmartPlug('192.168.xxx.xxx')

if plug.is_on:
    plug.turn_off()
    print('Plug turned off')
else:
    plug.turn_on()
    print('Plug turned on')