from upydevice import Device, DeviceException
import sys
import socket
import struct
import time
from datetime import datetime
import netifaces
import json
import os
import upydev


KEY_N_ARGS = {'du': ['f', 's'], 'df': ['s'], 'netstat_conn': ['wp'],
              'apconfig': ['ap'], 'i2c_config': ['i2c'],
              'spi_config': ['spi'], 'set_ntptime': ['utc']}

VALS_N_ARGS = ['f', 's', 'wp', 'ap', 'i2c', 'spi', 'utc']

ADC_PINS_DICT = {'esp32h': [i for i in range(32, 40)]}

ATTEN_DICT = {0: 'ADC.ATTN_0DB', 1: 'ADC.ATTN_2_5DB', 2: 'ADC.ATTN_6DB',
              3: 'ADC.ATTN_11DB'}
ATTEN_INFO = """
0 = ADC.ATTN_0DB: 0dB attenuation, gives a maximum input voltage of 1.00v
1 = ADC.ATTN_2_5DB: 2.5dB attenuation, gives a maximum input voltage of approximately 1.34v
2 = ADC.ATTN_6DB: 6dB attenuation, gives a maximum input voltage of approximately 2.00v
3 = ADC.ATTN_11DB: 11dB attenuation, gives a maximum input voltage of approximately 3.6v
"""

PROTOTYPE_COMMANDS_HELP = """
> PROTOTYPE: Usage '$ upydev COMMAND [opts]'
    COMMAND:
        >INPUT
        Sensors:
            * ADC:
                ^ON BOARD ADCS:
                - adc_config : to config analog pin to read from (see pinout, -po and -att)
                - aread : to read from an analog pin previously configured

                ^EXTERNAL ADC: (I2C) ADS1115 ***
                - ads_init : to initialize and configure ADS1115 and the channel to
                            read from (see -ads, -ch)
                - ads_read : to read from analog pin previously configured
                        (see -tm option for stream mode, and -f for logging*)
                        * for one shot read, logging is also available with -f and
                            -n option (for tagging)
                        * use '-f now' for automatic 'log_mode_datetime.txt' name.
                        * for stream mode profiling use -tm [ms] -ads test
            * IMU:
                - imu_init : initialize IMU, use -imu option to indicate the imu library.
                            (default option is 'lsm9ds1', see sensor requirements for more info')
                - imuacc : one shot read of the IMU lineal accelerometer (g=-9.8m/s^2),
                        (see -tm option for stream mode, and -f for logging*)
                        * for one shot read, logging is also available with -f and
                            -n option (for tagging)
                        * use '-f now' for automatic 'log_mode_datetime.txt' name.
                        * for stream mode profiling use -tm [ms] -imu test
                        ** stream mode and logging are supported in imugy and imumag also
                - imuacc_sd: log the imuacc data to the sd (must be mounted)
                            with the file format 'log_mode_datetime.txt'
                            (see -tm option for stream mode)
                - imugy :  one shot read of the IMU gyroscope (deg/s)
                - imumag : one shot read of the IMU magnetometer (gauss)
            * WEATHER SENSOR: (BME280)
                - bme_init: initialize bme, use -bme option to indicate the weather sensor library.
                            (default option is 'bme280', see sensor requirements for more info')
                - bme_read : to read values from bme (Temp(C), Pressure(Pa), Rel.Hummidity (percentage))
                        (see -tm option for stream mode, and -f for logging*)
                        * for one shot read, logging is also available with -f and
                            -n option (for tagging)
                        * use '-f now' for automatic 'log_mode_datetime.txt' name.
                        * for stream mode profiling use -tm [ms] -bme test
            * POWER SENSOR: (INA219)
                - ina_init: initialize ina, use -ina option to indicate the power sensor library.
                            (default option is 'ina219', see sensor requirements for more info')
                - ina_read : to read values from ina (Pot.Diff (Volts), Current(mA), Power(mW))
                        (see -tm option for stream mode, and -f for logging*)
                        * for one shot read, logging is also available with -f and
                            -n option (for tagging)
                        * use '-f now' for automatic 'log_mode_datetime.txt' name.
                        * for stream mode profiling use -tm [ms] -ina test
                - ina_batt: Use the sensor to profile battery usage and estimate battery life left.
                            It will made 100 measurements during 5 seconds. Indicate battery capacity
                            with -batt option; (in mAh)

        >OUTPUT:
            * DAC:
                - dac_config: to config analog pin to write to (use -po option)
                - dac_write: to write a value in volts (0-3.3V)
                - dac_sig: to write a signal use -sig for different options:
                          > [type] [Amp] [frequency]
                            (type: 'sin, sq'; Amp 0-1 V ; fq:0-50 (above that fq loses quality))
                          > start : starts signal generation
                          > stop : stops signal
                          > mod [Amp] [frequency]: modify the signal with the Amp and fq indicated.
            * BUZZER:
                - buzz_config: to config PWM pin to drive the buzzer (use -po option)
                - buzz_set_alarm: to set an alarm at time indicated with option -at, be
                                 aware that the rtc time must be set first with set_localtime
                                 or set_ntptime
                - buzz_interrupt: to configure an interrupt with pins indicated with -po,
                                use -md 'rev' for interrupt reverse operation
                - buzz_beep: make the buzzer beep, with options set by -opt,
                            usage: buzz_beep -opt [beep_ms] [number_of_beeps] [time_between_beeps] [fq]
            * DC MOTOR:
                - dcmotor_config: to config PWM pins to drive a DC motor (use -po option as -po [DIR1] [DIR2])
                - dcmotor_move: to move the motor to one direction ['R'] or the opposite ['L']
                                use -to option as -to ['R' or 'L'] [VELOCITY] (60-512)
                - dcmotor_stop: to stop the DC motor
            * SERVO:
                - servo_config: to configure the servo pin with -po option
                - servo_angle: to move the servo an angle indicated by -opt option
            * STEPPER MOTOR:
                - stepper_config: to configure the step and direction pin with -po option
                                    *( -po [DIR_PIN] [STEP_PIN])
                - stepper_move: to move the stepper to right or left, at a velocity and
                               a numbers of steps indicated with -to option: [R or L] [velocity] [# steps]
                               R: right, L:left, velocity (1000-20000) (smaller is faster) and
                               # steps (int), where 200 steps means a complete lap

        NETWORKING:
            * MQTT:
                - mqtt_config: to set id, broker address, user and password, use with -client option
                               as "mqtt_config -client [ID] [BROKER ADDRESS] [USER] [PASSWORD]"
                - mqtt_conn: to start a mqtt client and connect to broker; use mqtt_config first
                - mqtt_sub: to subscribe to a topic, use -to option as "mqtt_sub -to [TOPIC]"
                - mqtt_pub: to publish to a topic, use -to option as "mqtt_pub -to [TOPIC] [PAYLOAD]" or
                            "mqtt_pub -to [PAYLOAD]" if already subscribed to a topic.
                - mqtt_check: to check for new messages of the subscribed topics.
            * SOCKETS:
                - socli_init: to initiate a socket client use with -server option as
                              "socli_init -server [IP] [PORT] [BUFFER LENGTH]"
                - socli_conn: to connect the socket client to a server (inidcated by IP)
                - socli_send: to send a message to the server, use -n option to indicate
                              the message
                - socli_recv: to receive a message from the server
                - socli_close: to close the client socket
                - sosrv_init: to initiate a socket server, use with -server option as
                              "sosrv_init -server [PORT] [BUFFER LENGTH]"
                - sosrv_start: to start the server, waits for a connection
                - sosrv_send: to send a message to the client, use -n option to indicate
                              the message
                - sosrv_recv: to receive a message from the client
                - sosrv_close: to close the server socket
            * UREQUEST:
                - rget_json: to make a request to API that returns a JSON response format
                            (indicate API URL with -f option)
                - rget_text: to make a request to API that returns a text response format
                            (indicate API URL with -f option)

        Port/board specific commands:
        - battery : if running on battery, gets battery voltage (esp32 huzzah feather)
        - pinout : to see the pinout reference/info of a board, indicated by -b option,
                   to request a single or a list of pins info use -po option
        - specs : to see the board specs, indicated by -b option
        - pin_status: to see pin state, to request a specific set use -po option ***

        * ESP32: (Not implemented yet)
            - touch
            - hall
            - deepsleep
            - temp
"""


# def run_command_rl(command):
#     end = False
#     lines = []
#     process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
#     while end is not True:
#         if process.poll() is None:
#             output = process.stdout.readline()
#             if output == '' and process.poll() is not None:
#                 break
#             if output:
#                 line = output.strip().decode()
#                 lines.append(line)
#                 if output.strip() == b'### closed ###':
#                     end = True
#         else:
#             break
#     rc = process.poll()
#     return rc, lines


def get_ip():
    # scanoutput = subprocess.check_output(["ipconfig", "getifaddr", "en0"])
    # ip = scanoutput.decode('utf-8').split('\n')[0]
    try:
        ip = [netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'] for
              iface in netifaces.interfaces() if netifaces.AF_INET in
              netifaces.ifaddresses(iface)][-1]
        return ip
    except Exception as e:
        try:
            ip_soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            ip_soc.connect(('8.8.8.8', 1))
            local_ip = ip_soc.getsockname()[0]
            ip_soc.close()
            return local_ip
        except Exception as e:
            return '0.0.0.0'


def get_live_stream(args, run_cmd, dev, sensorlib, filename=None,
                    r_format='fff', nb=12, log=False, variables=None):
    if args.lh is None:
        local_ip = get_ip()
    if args.lh is not None:
        local_ip = args.lh

    # START A LOCAL SERVER
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((local_ip, 8005))
    server_socket.listen(1)
    dev.wr_cmd('{}.connect_SOC({})'.format(sensorlib, "'{}'".format(
                                                 local_ip)), silent=True, follow=False)
    # dev.disconnect()
    conn, addr = server_socket.accept()
    conn.settimeout(1)
    flushed = 0
    while flushed == 0:
        try:
            conn.recv(1024)
        except Exception as e:
            flushed = 1
    if args.tm > 500:
        conn.settimeout((args.tm/1000)*3)  # for long periodic shots
    dev.wr_cmd(run_cmd, silent=True, follow=False)
    print(('{:^15}'*len(variables)).format(*variables))
    try:
        if log:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      struct.unpack(r_format, data_acc)))
                    decode_print = dict(zip(variables,
                                            [format(val, '.4f') for val in struct.unpack(r_format, data_acc)]))
                    sys.stdout.write("\033[K")
                    print(('{:^15}'*len(decode_print.values())
                           ).format(*decode_print.values()), end='\r')
                    sys.stdout.flush()
                    with open(filename, 'a') as logfile:
                        logfile.write(json.dumps(decode))
                        logfile.write('\n')
                except Exception as e:
                    print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break
        else:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      [format(val, '.4f') for val in struct.unpack(r_format, data_acc)]))
                    sys.stdout.write("\033[K")
                    print(('{:^15}'*len(decode.values())
                           ).format(*decode.values()), end='\r')
                    sys.stdout.flush()
                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break

    except KeyboardInterrupt:
        try:
            print('\n')
            print('...closing...')
            conn.shutdown(socket.SHUT_RDWR)
            time.sleep(1)
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            print('Done!')
            conn.close()
        except KeyboardInterrupt:
            print('...wait for closing...')
            conn.shutdown(socket.SHUT_RDWR)
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            time.sleep(1)
            conn.close()
            print('Done!')
        dev.disconnect()


def test_stream(args, run_cmd, dev, sensorlib, filename=None,
                r_format='fff', nb=12, log=False, variables=None, BUFFERSIZE=1):
    if args.lh is None:
        local_ip = get_ip()
    if args.lh is not None:
        local_ip = args.lh

    # START A LOCAL SERVER
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((local_ip, 8005))
    server_socket.listen(1)
    dev.wr_cmd('{}.connect_SOC({})'.format(sensorlib, "'{}'".format(
                                                 local_ip)), silent=True, follow=False)
    conn, addr = server_socket.accept()
    conn.settimeout(1)
    flushed = 0
    while flushed == 0:
        try:
            conn.recv(1024)
        except Exception as e:
            flushed = 1
    if args.tm > 500:
        conn.settimeout((args.tm/1000)*3)  # for long periodic shots
    dev.wr_cmd(run_cmd, silent=True, follow=False)
    print(('{:^15}'*len(variables)).format(*variables))
    t0 = time.time()
    test_val = []
    try:
        if log:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      struct.unpack(r_format, data_acc)))
                    decode_print = dict(zip(variables,
                                            [format(val, '.4f') for val in struct.unpack(r_format, data_acc)]))
                    sys.stdout.write("\033[K")
                    print(('{:^15}'*len(decode_print.values())
                           ).format(*decode_print.values()), end='\r')
                    sys.stdout.flush()
                    with open(filename, 'a') as logfile:
                        logfile.write(json.dumps(decode))
                        logfile.write('\n')
                except Exception as e:
                    print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break
        else:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      struct.unpack(r_format, data_acc)))
                    decode_p = dict(zip(variables,
                                        [format(val, '.4f') for val in struct.unpack(r_format, data_acc)]))
                    sys.stdout.write("\033[K")
                    print(('{:^15}'*len(decode_p.values())
                           ).format(*decode_p.values()), end='\r')
                    sys.stdout.flush()
                    test_val.append(decode)
                    if t0 == 0:
                        t0 = time.time()

                    final_time = abs(time.time()-t0)
                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break

    except KeyboardInterrupt:
        try:
            print('\n')
            print('...closing...')
            conn.shutdown(socket.SHUT_RDWR)
            time.sleep(1)
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            print('Done!')
            print('TEST RESULTS ARE:')
            print('TEST DURATION : {} (s)'.format(final_time))
            # # FIND SAMPLING RATE
            # Method 1:
            N_DATA_PACKETS = len(test_val)  # Number of batches received
            print('DATA PACKETS : {} packets'.format(N_DATA_PACKETS))
            # (assuming al batches = buffer_size long)
            Fs = ((N_DATA_PACKETS+1)*BUFFERSIZE/final_time)
            print('SAMPLES PER PACKET : {}'.format(BUFFERSIZE))
            print('VARIABLES PER SAMPLE : {}; {}'.format(
                len(variables), variables))
            print('SIZE OF PACKETS: {} bytes'.format(nb))
            #  32 is batch/buffer size ,
            # so total samples is n_batches (len(vals)) x size_batch
            # print('Period: {} ms ; Fs:{} Hz'.format(
            # timestamp[:].mean()/1e3,1/((timestamp[:].mean())/1e6))
            conn.close()
            print('Period: {} ms ; Fs:{} Hz, Data send rate: {} packets/s of {} samples'.format(
                round((1/Fs)*1e3), round(Fs, -1),
                round(N_DATA_PACKETS/final_time), BUFFERSIZE))
            print(
                'DATA TRANSFER RATE: {} KB/s'.format(round(N_DATA_PACKETS/final_time)*nb/1024))
        except KeyboardInterrupt:
            conn.shutdown(socket.SHUT_RDWR)
            print('...wait for closing...')
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            time.sleep(1)
            conn.close()
            print('Done!')
        dev.disconnect()


def get_live_stream_chunk(args, run_cmd, dev, sensorlib, filename=None,
                          r_format='h'*20, nb=40, log=False, variables=None):
    if args.lh is None:
        local_ip = get_ip()
    if args.lh is not None:
        local_ip = args.lh

    # START A LOCAL SERVER
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((local_ip, 8005))
    server_socket.listen(1)
    dev.wr_cmd('{}.connect_SOC({})'.format(sensorlib, "'{}'".format(
                                                 local_ip)), silent=True, follow=False)
    conn, addr = server_socket.accept()
    conn.settimeout(1)
    flushed = 0
    while flushed == 0:
        try:
            conn.recv(1024)
        except Exception as e:
            flushed = 1
    if args.tm > 500:
        conn.settimeout((args.tm/1000)*3)  # for long periodic shots
    dev.wr_cmd(run_cmd, silent=True)
    time.sleep(0.5)
    print(('{:^15}'*len(variables)).format(*variables))
    try:
        if log:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      [struct.unpack(r_format, data_acc)]))
                    # print(decode)
                    for chunk in decode.values():
                        value = sum([val for val in chunk])/len(chunk)
                        sys.stdout.write("\033[K")
                        decode_p = dict(zip(variables,
                                            [format(value, '.4f')]))
                        print(('{:^15}'*len(decode_p.values())
                               ).format(*decode_p.values()), end='\r')
                        sys.stdout.flush()
                    with open(filename, 'a') as logfile:
                        logfile.write(json.dumps(decode))
                        logfile.write('\n')
                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break
        else:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      [struct.unpack(r_format, data_acc)]))
                    # print(decode)
                    for chunk in decode.values():
                        value = sum([val for val in chunk])/len(chunk)
                        sys.stdout.write("\033[K")
                        decode_p = dict(zip(variables,
                                            [format(value, '.4f')]))
                        print(('{:^15}'*len(decode_p.values())
                               ).format(*decode_p.values()), end='\r')
                        sys.stdout.flush()
                        # print(dict(zip(variables, [value])))

                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        print(e)
                        break

    except KeyboardInterrupt:
        try:
            print('\n')
            print('...closing...')
            conn.shutdown(socket.SHUT_RDWR)
            time.sleep(1)
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            print('Done!')
            conn.close()
        except KeyboardInterrupt:
            conn.shutdown(socket.SHUT_RDWR)
            print('...wait for closing...')
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            time.sleep(1)
            conn.close()
            print('Done!')
        dev.disconnect()


def test_stream_chunk(args, run_cmd, dev, sensorlib, filename=None,
                      r_format='h'*20, nb=40, log=False, variables=None, BUFFERSIZE=20):
    if args.lh is None:
        local_ip = get_ip()
    if args.lh is not None:
        local_ip = args.lh

    # START A LOCAL SERVER
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((local_ip, 8005))
    server_socket.listen(1)
    dev.wr_cmd('{}.connect_SOC({})'.format(sensorlib, "'{}'".format(
                                                 local_ip)), silent=True, follow=False)
    conn, addr = server_socket.accept()
    conn.settimeout(1)
    flushed = 0
    while flushed == 0:
        try:
            conn.recv(1024)
        except Exception as e:
            flushed = 1
    if args.tm > 500:
        conn.settimeout((args.tm/1000)*3)  # for long periodic shots
    dev.wr_cmd(run_cmd, silent=True)
    time.sleep(0.5)
    t0 = time.time()
    test_val = []
    print(('{:^15}'*len(variables)).format(*variables))
    try:
        if log:
            while True:
                try:
                    data_acc = conn.recv(nb)
                    decode = dict(zip(variables,
                                      [struct.unpack(r_format, data_acc)]))
                    # print(decode)
                    for chunk in decode.values():
                        value = sum([val for val in chunk])/len(chunk)
                        sys.stdout.write("\033[K")
                        decode_p = dict(zip(variables,
                                            [format(value, '.4f')]))
                        print(('{:^15}'*len(decode_p.values())
                               ).format(*decode_p.values()), end='\r')
                        sys.stdout.flush()
                    with open(filename, 'a') as logfile:
                        logfile.write(json.dumps(decode))
                        logfile.write('\n')
                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break
        else:
            while True:
                try:
                    data_recv = conn.recv(nb)
                    decode = dict(zip(variables,
                                      [struct.unpack(r_format, data_recv)]))
                    # print(decode)
                    for chunk in decode.values():
                        value = sum([val for val in chunk])/len(chunk)
                        sys.stdout.write("\033[K")
                        decode_p = dict(zip(variables,
                                            [format(value, '.4f')]))
                        print(('{:^15}'*len(decode_p.values())
                               ).format(*decode_p.values()), end='\r')
                        sys.stdout.flush()
                    test_val.append(decode)
                    if t0 == 0:
                        t0 = time.time()

                    final_time = abs(time.time()-t0)
                except Exception as e:
                    # print(e)
                    if str(e) == 'timed out':
                        pass
                    else:
                        break

    except KeyboardInterrupt:
        try:
            print('\n')
            print('...closing...')
            conn.shutdown(socket.SHUT_RDWR)
            time.sleep(1)
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            print('Done!')
            print('TEST RESULTS ARE:')
            print('TEST DURATION : {} (s)'.format(final_time))
            # # FIND SAMPLING RATE
            # Method 1:
            N_DATA_PACKETS = len(test_val)  # Number of batches received
            print('DATA PACKETS : {} packets'.format(N_DATA_PACKETS))
            # (assuming al batches = buffer_size long)
            Fs = ((N_DATA_PACKETS+1)*BUFFERSIZE/final_time)
            print('SAMPLES PER PACKET : {}'.format(BUFFERSIZE))
            print('VARIABLES PER SAMPLE : {}; {}'.format(
                len(variables), variables))
            print('SIZE OF PACKETS: {} bytes'.format(nb))
            #  32 is batch/buffer size ,
            # so total samples is n_batches (len(vals)) x size_batch
            # print('Period: {} ms ; Fs:{} Hz'.format(
            # timestamp[:].mean()/1e3,1/((timestamp[:].mean())/1e6))
            conn.close()
            print('Period: {} ms ; Fs:{} Hz, Data send rate: {} packets/s of {} samples'.format(
                round((1/Fs)*1e3), round(Fs, -1),
                round(N_DATA_PACKETS/final_time), BUFFERSIZE))
            print(
                'DATA TRANSFER RATE: {} KB/s'.format(round(N_DATA_PACKETS/final_time)*nb/1024))
        except KeyboardInterrupt:
            conn.shutdown(socket.SHUT_RDWR)
            print('...wait for closing...')
            # Flush error keyboardinterrupt
            cmd = '{}.stop_send();gc.collect()'.format(sensorlib)
            dev.wr_cmd(cmd, silent=True)
            time.sleep(1)
            conn.close()
            print('Done!')

        dev.disconnect()


# LOGGING DATETIME NOW:
def lognow(filename, sensor):
    if filename == 'now':
        return 'log_{}_{}.txt'.format(sensor,
                                      datetime.now().strftime("%m_%d_%Y_%H_%M_%S"))
    else:
        return filename


def prototype_command(args, **kargs):
    if args.m == 'pro':
        print(PROTOTYPE_COMMANDS_HELP)

    #############################################
    # SENSOR SPECIFIC COMMANDS

    #  * ADC *

    # ADC CONFIG
    # dev_name = kargs.get('device')
    # dt = check_device_type(args.t)
    elif args.m == 'adc_config':
        if args.att == 'info':
            print(ATTEN_INFO)
        else:
            if args.b is not None:
                print('Available ADC pins for {} board are : {}'.format(
                    args.b, ADC_PINS_DICT[args.b]))
            else:
                adc_pin = args.po[0]
                analog_cmd = "from machine import ADC,Pin;analog_pin = ADC(Pin({}));".format(
                    adc_pin)
                analog_atten = "analog_pin.atten({});gc.collect()".format(
                    ATTEN_DICT[int(args.att)])
                adc_cmd = analog_cmd + analog_atten
                dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
                dev.wr_cmd(adc_cmd)
                dev.disconnect()
                print('Pin {} configured as Analog Input with {} attenuation'.format(
                    adc_pin, ATTEN_DICT[int(args.att)][4:]))
            sys.exit()

    # ADC READ
    elif args.m == 'aread':
        adc_cmd = "((analog_pin.read())/4095)*3.6;gc.collect()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        analog_info = dev.wr_cmd(adc_cmd, silent=True, rtn_resp=True)
        dev.disconnect()
        if analog_info:
            volts = analog_info
            print('Volts: {}'.format(volts))
        sys.exit()

    # * ADS *
    # ADS_INIT
    elif args.m == 'ads_init':
        ads_lib = args.ads
        import_ads_cmd = "from {} import {};import init_ADS as ads;".format(
            args.ads, args.ads.upper())
        print('Initialazing ads...')
        ads_init_cmd = "my_ads = ads.MY_ADS({},ads.i2c,None,channel={});".format(
            args.ads.upper(), args.ch)
        if args.i2c != [22, 23]:
            ads_init_cmd = "{};my_ads = ads.MY_ADS({},{},None,channel={});".format(
                'from machine import I2C', args.ads.upper(), 'I2C(scl=Pin({}), sda=Pin({}))'.format(*args.i2c), args.ch)
        ads_final_init = "my_ads.init();gc.collect()"
        ads_init_cmd_str = import_ads_cmd + ads_init_cmd + ads_final_init
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

        dev.wr_cmd(ads_init_cmd_str)
        dev.disconnect()
        sys.exit()

    # ADS_READ
    elif args.m == 'ads_read':
        if args.tm is None:
            ads_cmd = "my_ads.read_V();"
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            ads_info = dev.wr_cmd(ads_cmd, silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
            dev.disconnect()
            if ads_info:
                my_read = round(ads_info, 2)
                print('{} V'.format(my_read))
                if args.f is not None:
                    data_shot = [my_read]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {'VAR': ['V', 'TS'], 'UNIT': 'Volts'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))

        elif args.ads == 'test':
            stream_ads = "my_ads.start_send(my_ads.chunk_send_V,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            ch = dev.wr_cmd('my_ads.channel', silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            # dev.disconnect()
            print('Streaming ADS: A{} (voltage),fq={}Hz'.format(ch, fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['V'], 'UNIT': 'VOLTS',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                test_stream_chunk(args, stream_ads, dev, 'my_ads',
                                  filename=args.f, log=True,
                                  r_format='f'*20, nb=80, variables=header['VAR'])
            else:
                header = {'VAR': ['V'], 'UNIT': 'VOLTS',
                          'fq(hz)': fq}
                test_stream_chunk(args, stream_ads, dev, 'my_ads',
                                  variables=header['VAR'], r_format='f'*20, nb=80)
        else:
            # Do connect
            stream_ads = "my_ads.start_send(my_ads.chunk_send_V,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            ch = dev.wr_cmd('my_ads.channel', silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            # dev.disconnect()
            print('Streaming ADS: A{} (voltage),fq={}Hz'.format(ch, fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['V'], 'UNIT': 'VOLTS',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream_chunk(args, stream_ads, dev, 'my_ads',
                                      filename=args.f, log=True,
                                      r_format='f'*20, nb=80, variables=header['VAR'])
            else:
                header = {'VAR': ['V'], 'UNIT': 'VOLTS',
                          'fq(hz)': fq}
                get_live_stream_chunk(args, stream_ads, dev, 'my_ads',
                                      variables=header['VAR'], r_format='f'*20, nb=80)
        sys.exit()
    # * IMU *
    # IMU_INIT

    elif args.m == 'imu_init':
        imu_lib = args.imu
        import_imu_cmd = "from {} import {};import init_IMU as imu;".format(
            args.imu, args.imu.upper())
        print('Initialazing imu...')
        imu_init_cmd = "my_imu = imu.MY_IMU({},imu.i2c,None);".format(
            args.imu.upper())
        if args.i2c != [22, 23]:
            imu_init_cmd = "{};my_imu = imu.MY_IMU({},{},None);".format(
                'from machine import I2C', args.imu.upper(), 'I2C(scl=Pin({}), sda=Pin({}))'.format(*args.i2c))
        imu_final_init = "my_imu.init()"
        imu_init_cmd_str = import_imu_cmd + imu_init_cmd + imu_final_init
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(imu_init_cmd_str)
        dev.disconnect()
        sys.exit()

    #  IMUACC

    elif args.m == 'imuacc':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.tm is None:
            imu_cmd = "my_imu.read_acc()"
            # dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            imu_info = dev.wr_cmd(imu_cmd, silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)

            dev.disconnect()
            if imu_info:
                print('X:{},Y:{},Z:{}'.format(*imu_info))
                if args.f is not None:
                    data_shot = [*imu_info]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {'VAR': ['X', 'Y', 'Z', 'TS'], 'UNIT': 'g=-9.8m/s^2'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))
        elif args.imu == 'test':
            # Do connect
            stream_acc = "my_imu.start_send(my_imu.sample_send_acc,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_imu", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming IMU ACCELEROMETER: X, Y, Z (g=-9.8m/s^2),fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'g=-9.8m/s^2',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                test_stream(args, stream_acc, dev, 'my_imu',
                            filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'g=-9.8m/s^2',
                          'fq(hz)': fq}
                test_stream(args, stream_acc, dev, 'my_imu',
                            variables=header['VAR'])

        else:
            # Do connect
            stream_acc = "my_imu.start_send(my_imu.sample_send_acc,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            dev.wr_cmd("my_imu", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            fq = 1/(args.tm/1000)
            print('Streaming IMU ACCELEROMETER: X, Y, Z (g=-9.8m/s^2),fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'g=-9.8m/s^2',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream(args, stream_acc, dev, 'my_imu',
                                filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'g=-9.8m/s^2',
                          'fq(hz)': fq}
                get_live_stream(args, stream_acc, dev, 'my_imu',
                                variables=header['VAR'])

        sys.exit()

    # IMUACC SD
    elif args.m == 'imuacc_sd':
        # Do connect
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        fq = 1/(args.tm/1000)
        header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'g=-9.8m/s^2',
                  'fq(hz)': fq}
        stream_acc = "my_imu.start_send_SD(my_imu.sample_send_acc_SD,'ACC','{}',timeout={})".format(
            header['UNIT'], args.tm)
        # run_live(stream_acc, args.t, args.p)
        # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
        dev.wr_cmd("my_imu", silent=True, rtn_resp=True)
        if dev._traceback.decode() in dev.response:
            try:
                raise DeviceException(dev.response)
            except Exception as e:
                print(e)
                dev.disconnect()
                sys.exit()
        print('Streaming IMU ACCELEROMETER: X, Y, Z (g=-9.8m/s^2),fq={}Hz'.format(fq))
        get_live_stream(args, stream_acc, dev, 'my_imu',
                        variables=header['VAR'])
    # IMUGY

    elif args.m == 'imugy':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.tm is None:
            imu_cmd = "my_imu.read_gy()"
            # dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            imu_info = dev.wr_cmd(imu_cmd, silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
            dev.disconnect()
            if imu_info:
                print('X:{},Y:{},Z:{}'.format(*imu_info))
                if args.f is not None:
                    data_shot = [*imu_info]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {'VAR': ['X', 'Y', 'Z', 'TS'], 'UNIT': 'deg/s'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))
        else:
            # Do connect
            stream_ = "my_imu.start_send(my_imu.sample_send_gy,timeout={})".format(
                args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_imu", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming IMU GYRO: X, Y, Z (deg/s),fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'deg/s',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream(args, stream_, dev, 'my_imu',
                                filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'deg/s',
                          'fq(hz)': fq}
                get_live_stream(args, stream_, dev, 'my_imu',
                                variables=header['VAR'])

        sys.exit()

    # IMUMAG

    elif args.m == 'imumag':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.tm is None:
            imu_cmd = "my_imu.read_mag()"
            # dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            imu_info = dev.wr_cmd(imu_cmd, silent=True, rtn_resp=True)

            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)

            dev.disconnect()
            if imu_info:
                print('X:{},Y:{},Z:{}'.format(*imu_info))
                if args.f is not None:
                    data_shot = [*imu_info]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {'VAR': ['X', 'Y', 'Z', 'TS'], 'UNIT': 'gauss'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))
        else:
            # Do connect
            stream_ = "my_imu.start_send(my_imu.sample_send_mag,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_imu", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming IMU MAGNETOMETER: X, Y, Z (gauss),fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'gauss',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream(args, stream_, dev, 'my_imu',
                                filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['X', 'Y', 'Z'], 'UNIT': 'gauss',
                          'fq(hz)': fq}
                get_live_stream(args, stream_, dev, 'my_imu',
                                variables=header['VAR'])

        sys.exit()

    # * BME280 *
    # BME_INIT

    elif args.m == 'bme_init':
        bme_lib = args.bme
        import_bme_cmd = "from {} import {};import init_BME280 as bme280;".format(
            args.bme, args.bme.upper())
        print('Initialazing bme280...')
        bme_init_cmd = "my_bme = bme280.MY_BME280({},bme280.i2c);".format(
            args.bme.upper())
        if args.i2c != [22, 23]:
            bme_init_cmd = "{};my_bme = bme280.MY_BME280({},{});".format(
                'from machine import I2C', args.bme.upper(), 'I2C(scl=Pin({}), sda=Pin({}))'.format(*args.i2c))
        bme_final_init = "my_bme.init()"
        bme_init_cmd_str = import_bme_cmd + bme_init_cmd + bme_final_init
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

        dev.wr_cmd(bme_init_cmd_str)
        dev.disconnect()
        sys.exit()

    #  BME_READ

    elif args.m == 'bme_read':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.tm is None:
            bme_cmd = "my_bme.read_values()"
            # dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            bme_info = dev.wr_cmd(bme_cmd, silent=True, rtn_resp=True)
            dev.wr_cmd("my_bme", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)

            dev.disconnect()
            if bme_info:
                print('{} C, {} Pa , {} % RH '.format(*bme_info))
                if args.f is not None:
                    data_shot = [*bme_info]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {
                        'VAR': ['Temp(C)', 'Pressure(Pa)', 'RH(%)', 'TS'], 'UNIT': 'T: C; P: Pa; RH: %'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))
        elif args.bme == 'test':
            # Do connect
            stream_bme = "my_bme.start_send(my_bme.sample_send_data,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_bme", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming BME280: Temp (C), Pressure (Pa), Rel. Hummidity (%) ,fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['Temp(C)', 'Pressure(Pa)', 'RH(%)', 'TS'], 'UNIT': 'T: C; P: Pa; RH: %',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                test_stream(args, stream_bme, dev, 'my_bme',
                            filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['Temp(C)', 'Pressure(Pa)', 'RH(%)', 'TS'], 'UNIT': 'T: C; P: Pa; RH: %',
                          'fq(hz)': fq}
                test_stream(args, stream_bme, dev, 'my_bme',
                            variables=header['VAR'])

        else:
            # Do connect
            stream_bme = "my_bme.start_send(my_bme.sample_send_data,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_bme", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming BME280: Temp (C), Pressure (Pa), Rel. Hummidity (%) ,fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['Temp(C)', 'Pressure(Pa)', 'RH(%)'], 'UNIT': 'T: C; P: Pa; RH: %',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream(args, stream_bme, dev, 'my_bme',
                                filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['Temp(C)', 'Pressure(Pa)', 'RH(%)'], 'UNIT': 'T: C; P: Pa; RH: %',
                          'fq(hz)': fq}
                get_live_stream(args, stream_bme, dev, 'my_bme',
                                variables=header['VAR'])

        sys.exit()

    # * INA219 *
    # INA_INIT

    elif args.m == 'ina_init':
        ina_lib = args.ina
        import_ina_cmd = "from {} import {};import init_INA219 as ina219;".format(
            args.ina, args.ina.upper())
        print('Initialazing ina219...')
        ina_init_cmd = "my_ina = ina219.MY_INA219({},ina219.i2c);".format(
            args.ina.upper())
        if args.i2c != [22, 23]:
            ina_init_cmd = "{};my_ina = ina219.MY_INA219({},{});".format(
                'from machine import I2C', args.ina.upper(), 'I2C(scl=Pin({}), sda=Pin({}))'.format(*args.i2c))
        ina_final_init = "my_ina.init()"
        ina_init_cmd_str = import_ina_cmd + ina_init_cmd + ina_final_init
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(ina_init_cmd_str)
        dev.disconnect()
        sys.exit()

    #  INA_READ

    elif args.m == 'ina_read':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.tm is None:
            ina_cmd = "my_ina.read_values()"
            # dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

            ina_info = dev.wr_cmd(ina_cmd, silent=True, rtn_resp=True)
            dev.wr_cmd("my_ina", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)

            dev.disconnect()
            if ina_info:
                print('{} V, {} mA , {} mW '.format(*ina_info))
                if args.f is not None:
                    data_shot = [*ina_info]
                    tag_tstamp = datetime.now().strftime("%H:%M:%S")
                    time_stamp = tag_tstamp
                    if args.n is not None:
                        tag_tstamp = args.n
                    data_shot.append(tag_tstamp)
                    header = {'VAR': [
                        'Voltage(V)', 'Current(mA)', 'Power(mW)', 'TS'], 'UNIT': 'V: v; C: mA; P: mW'}
                    if args.f not in os.listdir():
                        with open(args.f, 'w') as file_log:
                            file_log.write(json.dumps(header))
                            file_log.write('\n')
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    else:
                        with open(args.f, 'a') as file_log:
                            file_log.write(json.dumps(dict(zip(header['VAR'],
                                                               data_shot))))
                            file_log.write('\n')
                    print('Logged at {}'.format(time_stamp))
        elif args.ina == 'test':
            # Do connect
            stream_ina = "my_ina.start_send(my_ina.sample_send_data,timeout={})".format(
                args.tm)
            # run_live(stream_acc, args.t, args.p)
            # "imu.stream_acc(soc=cli_soc, timeout={})".format(args.tm)
            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_ina", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming ina219: Volts (V), Current (mA), Power (mW) ,fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['Voltage(V)', 'Current(mA)', 'Power(mW)'], 'UNIT': 'V: v; C: mA; P: mW',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                test_stream(args, stream_ina, dev, 'my_ina',
                            filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['Voltage(V)', 'Current(mA)', 'Power(mW)'], 'UNIT': 'V: v; C: mA; P: mW',
                          'fq(hz)': fq}
                test_stream(args, stream_ina, dev, 'my_ina',
                            variables=header['VAR'])

        else:
            # Do connect
            stream_ina = "my_ina.start_send(my_ina.sample_send_data,timeout={})".format(
                args.tm)

            fq = 1/(args.tm/1000)
            dev.wr_cmd("my_ina", silent=True, rtn_resp=True)
            if dev._traceback.decode() in dev.response:
                try:
                    raise DeviceException(dev.response)
                except Exception as e:
                    print(e)
                    dev.disconnect()
                    sys.exit()
            print('Streaming ina219: Volts (V), Current (mA), Power (mW) ,fq={}Hz'.format(fq))
            if args.f is not None:
                args.f = lognow(args.f, args.m)
                print('Saving file {} ...'.format(args.f))
                header = {'VAR': ['Voltage(V)', 'Current(mA)', 'Power(mW)'], 'UNIT': 'V: v; C: mA; P: mW',
                          'fq(hz)': fq}
                with open(args.f, 'w') as file_log:
                    file_log.write(json.dumps(header))
                    file_log.write('\n')
                get_live_stream(args, stream_ina, dev, 'my_ina',
                                filename=args.f, log=True, variables=header['VAR'])
            else:
                header = {'VAR': ['Voltage(V)', 'Current(mA)', 'Power(mW)'], 'UNIT': 'V: v; C: mA; P: mW',
                          'fq(hz)': fq}
                get_live_stream(args, stream_ina, dev, 'my_ina',
                                variables=header['VAR'])

        sys.exit()

    # INA_BATT
    elif args.m == 'ina_batt':
        print('\n')
        print(' {:>15}'.format('Battery Life expectancy profiling... '))
        ina_cmd = "my_ina.batt_ts_raw()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

        ina_info = dev.wr_cmd(ina_cmd, silent=True, rtn_resp=True)
        if dev._traceback.decode() in dev.response:
            try:
                raise DeviceException(dev.response)
            except Exception as e:
                print(e)
        dev.disconnect()
        if ina_info:
            volts_v, current_v, power_v = ina_info['V'], ina_info['C'], ina_info['P']
            volts = sum(volts_v)/len(volts_v)
            current = sum(current_v)/len(current_v)
            power = sum(power_v)/len(power_v)
            print('\n')
            print('{0:^15} {1:^15}'.format(
                '', '{}  {:>15}  {:>15}'.format('VOLTAGE', 'CURRENT', 'POWER')))
            print('  {0:>15}'.format('='*60))
            print('{0:^15} {1:^15}'.format('| Average |',
                                           '{:.2f} V {:>15.2f} mA  {:>15.2f} mW '.format(volts, current, power)))
            print('{0:^15}'.format('-'*len('| Average |')))
            print('{0:^15} {1:^15}'.format('|   MAX   |', '{:.2f} V {:>15.2f} mA  {:>15.2f} mW '.format(
                max(volts_v), max(current_v), max(power_v))))
            print('{0:^15}'.format('-'*len('| Average |')))
            print('{0:^15} {1:^15}'.format('|   MIN   |', '{:.2f} V {:>15.2f} mA  {:>15.2f} mW '.format(
                min(volts_v), min(current_v), min(power_v))))
            print('{0:^15}'.format('-'*len('| Average |')))
            print('\n')
            if current > 0:
                state = 'Discharging'
            else:
                state = 'Charging'
            percentage = round((volts-3.3)/(4.23-3.4)*100, 1)
            batt_le_full = (args.batt[0]/current)*0.70
            batt_le_now = round((batt_le_full * percentage)/100, 2)
            header = ' | {0:^15} | {1:^15} | {2:^15} | {3:^15} | {4:^20}  |'.format(
                'CAPACITY (mAh)', 'VOLTAGE (V)', 'LEVEL (%)', 'STATE', 'TIME LEFT (Hours)')
            print('  {0:^15}   {1:^15}   {2:^15}   {3:^15}   {4:^20}  '.format(
                '', '', 'BATTERY INFO', '', ''))
            print(' {0:>15}'.format('='*(len(header)-1)))
            print(header)
            print(' {0:>15}'.format('-'*(len(header)-1)))
            # print('| {0:^15} | {1:^15} | {2:^15} | {3:^15} | {4:^20} |'.format('', '', '', '', ''))
            print(' | {0:^15} | {1:^15.2f} | {2:^15} | {3:^15} | {4:^20}  |'.format(
                args.batt[0], volts, percentage, state, batt_le_now))
            # print('| {0:^15} | {1:^15} | {2:^15} | {3:^15} | {4:^20} |'.format('', '', '', '', ''))
            # print(' {0:>15}'.format('='*len(header)))
            print('\n')
            # if args.f is not None:
            #     data_shot = [*ast.literal_eval(ina_info_list[0])]
            #     tag_tstamp = datetime.now().strftime("%H:%M:%S")
            #     time_stamp = tag_tstamp
            #     if args.n is not None:
            #         tag_tstamp = args.n
            #     data_shot.append(tag_tstamp)
            #     header = {'VAR': ['Voltage(V)', 'Current(mA)', 'Power(mW)', 'TS'], 'UNIT': 'V: v; C: mA; P: mW'}
            #     if args.f not in os.listdir():
            #         with open(args.f, 'w') as file_log:
            #             file_log.write(json.dumps(header))
            #             file_log.write('\n')
            #             file_log.write(json.dumps(dict(zip(header['VAR'],
            #                                                data_shot))))
            #             file_log.write('\n')
            #     else:
            #         with open(args.f, 'a') as file_log:
            #             file_log.write(json.dumps(dict(zip(header['VAR'],
            #                                                data_shot))))
            #             file_log.write('\n')
            #     print('Logged at {}'.format(time_stamp))
    #############################################
    # * DAC *

    # DAC CONFIG
    elif args.m == 'dac_config':
        if args.b is not None:
            print('Available DAC pins for {} board are : {}'.format(
                args.b, ADC_PINS_DICT[args.b]))
        else:
            dac_pin = args.po[0]
            analog_cmd = "from machine import DAC;analogdac_pin = DAC(Pin({}));".format(
                dac_pin)
            dac_cmd = analog_cmd
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            dev.wr_cmd(dac_cmd)
            dev.disconnect()
            print('Pin {} configured as Analog Output'.format(
                dac_pin))
        sys.exit()

    # DAC WRITE ## 8 BITS, 0-255
    elif args.m == 'dac_write':
        val_from_v = int((float(args.sig[0])/3.3)*255)
        analog_write = "analogdac_pin.write({});gc.collect()".format(val_from_v)
        dac_cmd = analog_write
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(dac_cmd)
        dev.disconnect()
        sys.exit()


    # DAC_SIG

    elif args.m == 'dac_sig':
        cmds = ['start', 'stop', 'mod']
        if args.sig[0] not in cmds:
            signal_class = "from dac_signal_gen import SIGNAL_GENERATOR;"
            signal_cmd = "sig=SIGNAL_GENERATOR(analogdac_pin,'{}',{},{})".format(
                *args.sig)
            conf_dac_sig = signal_class + signal_cmd
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            dev.wr_cmd(conf_dac_sig)
            print('Signal type {} with Amplitude {} V and fq {} Hz configured'.format(
                *args.sig))
        elif args.sig[0] == cmds[0]:
            signal_cmd = "sig.start()"
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            dev.wr_cmd(signal_cmd)
            print('Signal started!')

        elif args.sig[0] == cmds[1]:
            signal_cmd = "sig.stop()"
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            dev.wr_cmd(signal_cmd)
            print('Signal stopped!')

        elif args.sig[0] == cmds[2]:
            signal_cmd = "sig.modsig({},{})".format(args.sig[1], args.sig[2])
            dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
            dev.wr_cmd(signal_cmd)
            print('Signal modified to Amplitude: {} V, fq: {} Hz'.format(
                args.sig[1], args.sig[2]))

        dev.disconnect()
        sys.exit()

    #############################################
    # * BUZZER *
    # BUZZ CONFIG
    elif 'buzz' in args.m:
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        if args.m == 'buzz_config':
            BUZZ_pin = args.po[0]
            buzz_cmd = "from buzzertools import BUZZER;my_buzz = BUZZER({});".format(
                BUZZ_pin)

            dev.wr_cmd(buzz_cmd, silent=True)
            print('Pin {} configured as PWM to drive the buzzer'.format(
                BUZZ_pin))

        # BUZZ SET_ALARM
        elif args.m == 'buzz_set_alarm':
            if len(args.at) < 3:
                hour, minute = args.at
                seconds = 0
            else:
                hour, minute, seconds = args.at
            buzz_cmd = "my_buzz.set_alarm_at({},{},{});".format(hour, minute, seconds)

            dev.wr_cmd(buzz_cmd, silent=True)
            print('Alarm set at {}:{}:{}'.format(hour, minute, seconds))

        # BUZZ INTERRUPT
        elif args.m == 'buzz_interrupt':
            buzz_cmd = "my_buzz.active_button({},{});".format(*args.po)
            if args.md is not None:
                if args.md[0] == 'rev':
                    buzz_cmd = "my_buzz.active_button_rev({},{});".format(*args.po)

            dev.wr_cmd(buzz_cmd, silent=True)
            print('Button interrupt set at Pins; {},{}'.format(*args.po))

        # BUZZ BEEP
        elif args.m == 'buzz_beep':
            buzz_cmd = "my_buzz.buzz_beep({},{},{},{});".format(*args.opt)

            dev.wr_cmd(buzz_cmd, silent=True)
            print('Beep! '*args.opt[1])
        dev.disconnect()
        sys.exit()

    #############################################
    #  * MOTORS *

    #  * SERVO *
    # SERVO_CONFIG
    elif args.m == 'servo_config':
        servo_pin = args.po[0]
        servo_cmd = "from servo import Servo;my_servo = Servo(Pin({}));".format(
            servo_pin)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(servo_cmd)
        dev.disconnect()
        print('Pin {} configured as PWM to drive the Servo motor'.format(
            servo_pin))
        sys.exit()

    elif args.m == 'servo_angle':
        servo_angle = args.opt[0]
        servo_cmd = "my_servo.write_angle({});".format(
            servo_angle)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(servo_cmd)
        dev.disconnect()
        print('Servo moved to {} degrees!'.format(
            servo_angle))
        sys.exit()


    # * DC MOTOR *

    # DCMOTOR_CONFIG

    elif args.m == 'dcmotor_config':
        dir_pin, oppo_pin = args.po
        dcmotor_cmd = "from dcmotor import DCMOTOR;my_dcmotor = DCMOTOR({},{});".format(
            dir_pin, oppo_pin)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(dcmotor_cmd)
        dev.disconnect()
        print('DC motor configured: Direction Pin:{}, Opposite direction Pin: {}'.format(
            dir_pin, oppo_pin))
        sys.exit()

    # DCMOTOR_MOVE
    elif args.m == 'dcmotor_move':
        dcmotor_dir_dic = {'R': 0, 'L': 1}
        dcmotor_direction, velocity = args.to
        dcmotor_cmd = "my_dcmotor.move({},{});".format(
            dcmotor_dir_dic[dcmotor_direction], velocity)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(dcmotor_cmd)
        dev.disconnect()
        print('DC motor moving to {}!'.format(dcmotor_direction))
        sys.exit()

    # DCMOTOR_STOP
    elif args.m == 'dcmotor_stop':
        dcmotor_cmd = "my_dcmotor.stop();"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(dcmotor_cmd)
        dev.disconnect()
        print('DC motor stopped')
        sys.exit()
    # * STEPPER MOTOR *

    # STEPPER_CONFIG

    elif args.m == 'stepper_config':
        dir_pin, step_pin = args.po
        stepper_cmd = "from stepper import STEPPER;my_stepper = STEPPER({},{});".format(
            dir_pin, step_pin)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(stepper_cmd)
        dev.disconnect()
        print('Stepper motor configured: Direction Pin:{}, Step Pin: {}'.format(
            dir_pin, step_pin))
        sys.exit()

    # STEPPER_MOVE

    elif args.m == 'stepper_move':
        step_dir_dic = {'R': 0, 'L': 1}
        step_direction, velocity, steps = args.to
        stepper_cmd = "my_stepper.move_n_steps({},{},{});".format(
            step_dir_dic[step_direction], velocity, steps)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(stepper_cmd)
        dev.disconnect()
        print('Stepper moved {} steps to {} !'.format(
            steps, step_direction))
        sys.exit()


    #############################################
    #  * NETWORKING *

    #  * MQTT *

    # MQTT_CONFIG

    elif args.m == 'mqtt_config':
        if len(args.client) < 4:
            id, b_addr = args.client
            client_cmd = "from mqtt_client import mqtt_client ;my_mqtt = mqtt_client('{}','{}');".format(
                id, b_addr)
        else:
            id, b_addr, user, passwd = args.client
            client_cmd = "from mqtt_client import mqtt_client ;my_mqtt = mqtt_client('{}','{}',user = '{}', password = '{}');".format(
                id, b_addr, user, passwd)

        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(client_cmd)
        dev.disconnect()
        print('MQTT Client configured: ID: {}, BROKER: {}'.format(
            id, b_addr))
        sys.exit()

    # MQTT_CONN
    elif args.m == 'mqtt_conn':
        conn_cmd = "my_mqtt.connect();my_mqtt.set_def_callback();gc.collect()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(conn_cmd)
        dev.disconnect()
        print('MQTT Client connected!')
        sys.exit()

    # MQTT_SUB
    elif args.m == 'mqtt_sub':
        sub_cmd = "my_mqtt.subs('{}');gc.collect()".format(*args.to)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(sub_cmd)
        dev.disconnect()
        print('MQTT Client subscribed to TOPIC: {}'.format(*args.to))
        sys.exit()

    # MQTT_PUB
    elif args.m == 'mqtt_pub':
        if len(args.to) > 1:
            pub_cmd = "my_mqtt.pub(topic='{}',paylod='{}');gc.collect()".format(
                *args.to)
        else:
            pub_cmd = "my_mqtt.pub('{}');gc.collect()".format(*args.to)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(pub_cmd)
        dev.disconnect()
        if len(args.to) > 1:
            print('MQTT Client published message: {} to TOPIC: {}'.format(*args.to))
        else:
            print('MQTT Client published the message: {}'.format(*args.to))
        sys.exit()

    # MQTT_CHECK

    elif args.m == 'mqtt_check':
        check_cmd = "my_mqtt.check_msg();gc.collect()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(check_cmd)
        dev.disconnect()
        sys.exit()

    # * SOCKETS *

    # SOCLI_INIT
    elif args.m == 'socli_init':
        if len(args.server) > 2:
            host, port, buff = args.server
            socli_init_cmd = "my_cli=socket_client('{}',{},{})".format(
                host, port, buff)
        else:
            host, port = args.server
            socli_init_cmd = "my_cli=socket_client('{}',{})".format(host, port)
        socli_imp_cmd = "from socket_client_server import socket_client;"
        socli_comp_cmd = '{}{}'.format(socli_imp_cmd, socli_init_cmd)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(socli_comp_cmd)
        dev.disconnect()
        print('Initialized client socket to connect to server :{} on port {}'.format(host, port))
        sys.exit()

    # SOCLI_CONN
    elif args.m == 'socli_conn':
        socli_conn_cmd = "my_cli.connect_SOC();"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(socli_conn_cmd)
        dev.disconnect()

        print('Client connected!')
        sys.exit()

    # SOCLI_SEND
    elif args.m == 'socli_send':
        socli_send_cmd = "my_cli.send_message('{}');".format(args.n)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(socli_send_cmd)
        dev.disconnect()
        print('Message sent!')
        sys.exit()

    # SOCLI_RECV
    elif args.m == 'socli_recv':
        socli_recv_cmd = "my_cli.recv_message();"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(socli_recv_cmd)
        dev.disconnect()
        sys.exit()

    # SOCLI_CLOSE
    elif args.m == 'socli_close':
        socli_close_cmd = "my_cli.cli_soc.close();"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(socli_close_cmd)
        dev.disconnect()
        print('Client Socket closed!')
        sys.exit()

    # SOSRV_INIT
    elif args.m == 'sosrv_init':
        if len(args.server) > 1:
            port, buff = args.server
            sosrv_init_cmd = "my_serv=socket_server({},{})".format(port, buff)
        else:
            port = args.server[0]
            sosrv_init_cmd = "my_serv=socket_server({})".format(port)
        sosrv_imp_cmd = "from socket_client_server import socket_server;"
        sosrv_comp_cmd = '{}{}'.format(sosrv_imp_cmd, sosrv_init_cmd)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        serv_info = dev.wr_cmd(sosrv_comp_cmd, silent=True, rtn_resp=True)
        dev.disconnect()
        if len(serv_info) > 0:
            print('Server initialized. IP: {} PORT:{}'.format(serv_info, port))
        sys.exit()

    # SOSRV_START
    elif args.m == 'sosrv_start':
        sosrv_start_cmd = "my_serv.start_SOC();"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(sosrv_start_cmd)
        dev.disconnect()

        sys.exit()

    # SOSRV_SEND
    elif args.m == 'sosrv_send':
        sosrv_send_cmd = "my_serv.send_message('{}')".format(args.n)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(sosrv_send_cmd)
        dev.disconnect()
        print('Message sent!')
        sys.exit()

    # SOSRV_RECV
    elif args.m == 'sosrv_recv':
        sosrv_recv_cmd = "my_serv.recv_message()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(sosrv_recv_cmd)
        dev.disconnect()
        sys.exit()

    # SOSRV_CLOSE
    elif args.m == 'sosrv_close':
        sosrv_close_cmd = "my_serv.serv_soc.close()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(sosrv_close_cmd)
        dev.disconnect()
        print('Server Socket closed!')
        sys.exit()

    # * REQUEST *
    # RGET_JSON
    elif args.m == 'rget_json':
        rq_import_cmd = "import urequests as requests;"
        rq_query_cmd = "resp=requests.get('{}');".format(args.f)
        rq_json_cmd = "resp.json()"
        rq_comp_cmd = "{}{}{}".format(rq_import_cmd, rq_query_cmd, rq_json_cmd)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(rq_comp_cmd)
        dev.disconnect()
        sys.exit()

    # RGET_TEXT
    elif args.m == 'rget_text':
        rq_import_cmd = "import urequests as requests;"
        rq_query_cmd = "resp=requests.get('{}');".format(args.f)
        rq_text_cmd = "resp.text"
        rq_comp_cmd = "{}{}{}".format(rq_import_cmd, rq_query_cmd, rq_text_cmd)
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        dev.wr_cmd(rq_comp_cmd)
        dev.disconnect()
        sys.exit()
    #############################################
    #  * PORT SPECIFIC COMMANDS *

    # BATTERY

    elif args.m == 'battery':
        batt_cmd = "from machine import ADC;bat = ADC(Pin(35));bat.atten(ADC.ATTN_11DB);((bat.read()*2)/4095)*3.6;gc.collect()"
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)

        batlev = dev.wr_cmd(batt_cmd, silent=True, rtn_resp=True)
        dev.disconnect()
        try:
            if batlev > 0:
                volts = batlev
                percentage = round((volts - 3.3) / (4.23 - 3.3) * 100, 1)
                print('Battery Voltage : {} V; Level:{} %'.format(
                    round(volts, 2), percentage))
        except Exception as e:
            print('Battery Voltage : ? V; Level:? %')
        return

    # SPECS REF

    elif args.m == 'specs':
        try:
            board = args.b
            file_board = '{}/{}.config'.format(upydev.__path__[0], board)
            with open(file_board, 'r') as esp32ref:
                ref_dict = json.loads(esp32ref.read())

            print(ref_dict['SPECS'])

        except Exception as e:
            print("""reference board file not found""")
            sys.exit()

    # PIN OUT REF

    elif args.m == 'pinout':
        try:
            board = args.b
            file_board = '{}/{}.config'.format(upydev.__path__[0], board)
            with open(file_board, 'r') as esp32ref:
                ref_dict = json.loads(esp32ref.read())

            if args.po is not None:
                pin_query = args.po
                for query in pin_query:
                    print('PIN: {}: {}'.format(
                        query, ref_dict['PINOUT'][str(query)]))
            else:
                for key in ref_dict['PINOUT']:
                    print('PIN: {}: {}'.format(key, ref_dict['PINOUT'][key]))

        except Exception as e:
            print(str(e), ' Pin not Found or')
            print("""reference board file not found""")
            sys.exit()

        sys.exit()

    elif args.m == 'pin_status':
        dev = Device(args.t, args.p, init=True, ssl=args.wss, auth=args.wss)
        pinlist = "[16, 17, 26, 25, 34, 39, 36, 4, 21, 13, 12, 27, 33, 15, 32, 14, 22, 23, 5, 18, 19]"
        machine_pin = "pins=[machine.Pin(i, machine.Pin.IN) for i in pin_list]"
        status = "dict(zip([str(p) for p in pins],[p.value() for p in pins]))"
        pin_status_cmd = "import machine;pin_list={};{};{};gc.collect()".format(
            pinlist, machine_pin, status)
        pin_dict = dev.wr_cmd(pin_status_cmd, silent=True, rtn_resp=True)
        dev.disconnect()
        if pin_dict:
            if args.po is not None:
                pin_rqst = ['Pin({})'.format(po) for po in args.po]
                for key in pin_dict.keys():
                    if key in pin_rqst:
                        if pin_dict[key] == 1:
                            print('{0:^10} | {1:^5} | HIGH'.format(
                                key, pin_dict[key]))
                        else:
                            print('{0:^10} | {1:^5} |'.format(key, pin_dict[key]))

            else:
                for key in pin_dict.keys():
                    if pin_dict[key] == 1:
                        print('{0:^10} | {1:^5} | HIGH'.format(key, pin_dict[key]))
                    else:
                        print('{0:^10} | {1:^5} |'.format(key, pin_dict[key]))

        sys.exit()
