Example #1
0
    def test_ledrgb(self):
        """
        RGB LED Testing
        :return:
        """
        from enerpi.base import CONFIG
        from enerpi.ledrgb import get_rgbled, led_alarm, led_info, blink_color

        led = get_rgbled(verbose=True)
        if led is None:
            # PINOUT RGB_LED
            with_rgbled = CONFIG.getboolean('RGBLED', 'WITH_RGBLED', fallback=False)
            pin_r = CONFIG.getint('RGBLED', 'PIN_R', fallback=19)
            pin_g = CONFIG.getint('RGBLED', 'PIN_G', fallback=20)
            pin_b = CONFIG.getint('RGBLED', 'PIN_B', fallback=16)
            print('ERROR!! NO RGB LED. (WITH_LED={}; PINOUT_RGB=({},{},{})'.format(with_rgbled, pin_r, pin_g, pin_b))
            # assert 0
        else:
            print('TESTING RGB LED!')
            led_alarm(led, timeout=0)
            sleep(1)
            led_info(led, n=3)
            sleep(3)
            led_alarm(led, time_blinking=2.5, timeout=3)
            sleep(4)
            led_info(led, n=2)
            sleep(4)
            led_alarm(led, timeout=0)
            sleep(2)
            led_info(led, n=1)
            sleep(3)

            # Blinking:
            blink_color(led, (1, 0, 0), n=1)
            sleep(1)
            blink_color(led, (0, 1, 0), n=2)
            sleep(1)
            blink_color(led, (0, 0, 1), n=3)
            sleep(1)
            blink_color(led, (1, 1, 0), n=1)
            sleep(1)
            blink_color(led, (1, 0, 1), n=2)
            sleep(1)
            blink_color(led, (0, 1, 1), n=3)
            sleep(1)
            blink_color(led, (1, 1, 1), n=1)
            sleep(2)
            print('OK!!')
            led.close()
Example #2
0
def get_encryption_key(key_file=None):
    """
    Encryption key for symmetric encryption. URL-safe base64-encoded 32-byte key

    * Get local key, or exec wizard for making one.

    :param: key_file: :str: path of the file with the encryption key
    :return: :bytes: encryption_key
    """

    if key_file is None:
        key_file = os.path.join(DATA_PATH, CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key'))
    try:
        secret_key = open(key_file).read().encode()
    except FileNotFoundError:
        print('\033[0m\033[1m\033[34mCrypto KEY is missing.\033[0m Please, select one option:\n'
              '\t\033[1m1. Generate a new key.\n\t2. Input an existent key. (Copy&paste from another computer)')
        selec = input('\033[34mOPTION: \033[0m\033[31m')
        if selec == '1':
            secret_key = Fernet.generate_key()
        else:
            secret_key = input('*** KEY: ').encode()
        if len(secret_key) > 10:
            print('\033[0mThe new KEY ("{}")\nwill be saved in "{}"\n'.format(secret_key, key_file))
            open(key_file, 'wb').write(secret_key)
        else:
            print('\033[31;1mNot a valid KEY!:\n"{}". Try again... BYE!\033[0m'.format(secret_key))
            sys.exit(-1)
    return secret_key
Example #3
0
    def test_main_cli_data_plots(self):
        """
        CLI Testing patching sys.argv with unittest.mock

        """
        from enerpi.command_enerpi import enerpi_main_cli
        from enerpi.base import CONFIG

        dir_plots = os.path.join(self.DATA_PATH, CONFIG.get('ENERPI_DATA', 'IMG_BASEPATH'))
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '2016-10-01::2016-10-01', '-p', 'png', '-po', 'rm=30s'],
                                     test_mode=True)
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '::2016-10-04', '-p', 'png', '-po', 'rm=1h'],
                                     test_mode=True)
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '2016-10-25::2016-10-26', '-p', 'png', '-po', 'rs=30s'],
                                     test_mode=True)
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '2016-10-25::2016-10-30', '-p', 'png', '-po', 'rs=3min'],
                                     test_mode=True)
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '2016-10-21::2016-10-31', '-p', 'png', '-po', 'rs=30min'],
                                     test_mode=True)
        self.exec_func_with_sys_argv(enerpi_main_cli,
                                     ['test_cli', '-f', '2016-10-10::2016-10-30', '-p', 'png', '-po', 'rs=15min'],
                                     test_mode=True)
        # To get the plots for inspection:
        # os.system('cp -R {}/ ~/Desktop/test_plots'.format(dir_plots))
        self.assertEqual(len(os.listdir(dir_plots)), 6)
Example #4
0
 def test_0_config(self):
     from enerpi.base import CONFIG
     print(self.tmp_dir)
     print(self.DATA_PATH)
     print(self.cat)
     print(CONFIG.sections())
     for s in ['ENERPI_DATA', 'ENERPI_WEBSERVER', 'ENERPI_SAMPLER', 'BROADCAST', 'RGBLED']:
         pp.print_cyan(list(CONFIG[s].keys()))
         pp.print_red(list(CONFIG[s].values()))
Example #5
0
def make_cron_command_task_daemon():
    """
    CRON periodic task for exec ENERPI LOGGER as daemon at every boot
    Example command:
    */15 * * * * sudo -u www-data /home/pi/PYTHON/py35/bin/python
        /home/pi/PYTHON/py35/lib/python3.5/site-packages/enerpiweb/mule_rscgen.py -o

    :return: :str: cron_command
    """
    # cmd_logger = '@reboot sudo -u {user_logger} {python_pathbin}/enerpi-daemon start'
    cmd_logger = 'sudo -u {user_logger} {python_pathbin}/enerpi-daemon start'
    local_params = dict(user_logger=CONFIG.get('ENERPI_DATA', 'USER_LOGGER', fallback='pi'),
                        python_pathbin=os.path.dirname(sys.executable))
    return cmd_logger.format(**local_params)
Example #6
0
def test_www_data_in_rpi():
    """
    Test for check user & groups membership needed to run ENERPI with:
        · The ENERPI logger daemon, running every reboot with CRON
        · The ENERPI flask webserver, running under NGINX + UWSGI-EMPEROR

    """
    from enerpi.base import CONFIG

    def _formatted_test(user_t, groups_t, fix=False):
        print('*' * 80 + '\nTEST (u="{}", g="{}", fix=False):'.format(user_t, groups_t))
        res = _check_user_groups(user=user_t, desired_groups=groups_t, fix=fix)
        print('********** TEST RESULT = {} **********'.format(res) + '\n' + '*' * 80)
        return res

    if sys.platform == 'linux':  # RPI only test
        user_logger = CONFIG.get('ENERPI_DATA', 'USER_LOGGER', fallback='www-data')
        user_web = CONFIG.get('ENERPI_WEBSERVER', 'USER_SERVER', fallback='www-data')

        needed_groups = [('spi', ), ('gpio', 'kmem')]
        for user in [user_logger, user_web]:
            print('\nCHECKING GROUPS MEMBERSHIP FOR USER "{}"'.format(user))
            groups_exist = _checkoutput(['groups'])[1].split()
            user_exists, user_groups = _get_user_groups(user)
            print('EXISTENT GROUPS: "{}"'.format(groups_exist))
            print('GROUPS WITH USER {} (exist={}): "{}"'.format(user, user_exists, user_groups))
            assert user_exists
            for need in needed_groups:
                print('need: {}'.format(need))
                for g in need:
                    print('analysis g={}'.format(g))
                    if g in groups_exist:
                        print('{} in groups_exist'.format(g))
                        result = _formatted_test(user, [g], fix=True)
                        print('user: {} in group: {}? {}--> '.format(user, g, result))
                        assert result
                        break
Example #7
0
def receiver_msg_generator(verbose=True, n_msgs=None, port=None, codec=None):
    """
    Generador de mensajes en el receptor de la emisión en la broadcast IP. Recibe los mensajes y los desencripta.
    También devuelve los tiempos implicados en la recepción (~ el ∆T entre mensajes) y el proceso de desencriptado.
    :param verbose: :bool: Imprime Broadcast IP & PORT.
    :param n_msgs: :int: # de mensajes a recibir (ilimitados por defecto).
    :param port: :int: # de puerto de escucha.
    :param codec: :Fernet obj: Fernet object for decrypting msgs.
    :yield: msg, ∆T_msg, ∆T_decryp
    """
    if port is None:
        port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)
    if codec is None:
        codec = get_codec(get_encryption_key())

    sock, counter = None, 0
    udp_ip = _UDP_IP
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            sock.bind((udp_ip, port))
        except OSError as e:
            log('OSError --> {}. IP={}, PORT={}'.format(e, udp_ip, port),
                'error', verbose)
            raise KeyboardInterrupt
        log(_DESCRIPTION_IO.format(udp_ip, port), 'ok', verbose)
        while (n_msgs is None) or (counter < n_msgs):
            tic = time()
            data, addr = sock.recvfrom(1024)  # buffer size is 1024 bytes
            toc_msg = time()
            try:
                msg = codec.decrypt(data).decode()
            except InvalidToken as e:
                log(
                    'InvalidToken ERROR: {}. La clave es correcta?\n* KEY: "{}"'
                    .format(e, get_encryption_key()), 'error', verbose, True)
                break
            toc_dcry = time()
            yield msg, toc_msg - tic, toc_dcry - toc_msg
            counter += 1
        # log('Closing receiver_msg_generator socket...', 'debug', verbose, True)
    # except OSError as e:
    #     log('OSError {} en receiver_msg_generator'.format(e), 'error', verbose, True)
    except KeyboardInterrupt:
        log('KeyboardInterrupt en receiver_msg_generator', 'warn', verbose,
            True)
    if sock is not None:
        sock.close()
    raise StopIteration
Example #8
0
def _get_pb_obj():
    # Lazy load
    global PBOBJ

    if PBOBJ is None:
        try:
            pushbullet_token = CONFIG.get('NOTIFY', 'PUSHBULLET_TOKEN')
            if not pushbullet_token:
                raise InvalidKeyError
            PBOBJ = Pushbullet(pushbullet_token)
        except (NoOptionError, NoSectionError, InvalidKeyError) as e:
            log('NO Pushbullet config ({} [{}])'
                .format(e, e.__class__), 'error', False)
            PBOBJ = None
    return PBOBJ
Example #9
0
def broadcast_msg(msg,
                  counter_unreachable,
                  sock_send=None,
                  codec=None,
                  port=None,
                  verbose=True):
    """
    Emisión de datos en modo broadcast UDP (para múltiples receptores) como mensaje de texto encriptado.
    :param msg: Cadena de texto a enviar.
    :param counter_unreachable: np.array([0, 0]) de control de emisiones incorrectas (seguidas y totales)
    :param sock_send: Socket de envío broadcast. Se devuelve para su reutilización.
    :param codec: :Fernet obj: Fernet object for encrypting msgs.
    :param port: # de puerto de retransmisión.
    :param verbose: Imprime en stout mensajes de error y de envío de datos
    :return: sock_send
    """
    def _get_broadcast_socket(verb=False):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                             socket.IPPROTO_UDP)
        # sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        log(_DESCRIPTION_IO.format(_UDP_IP, port), 'ok', verb, verb)
        return sock

    if codec is None:
        codec = get_codec()
    if port is None:
        port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)
    if sock_send is None:
        sock_send = _get_broadcast_socket()
    encrypted_msg_b = codec.encrypt(msg.encode())
    try:
        sock_send.sendto(encrypted_msg_b, (_UDP_IP, port))
        counter_unreachable[0] = 0
    except OSError as e:  # [Errno 101] Network is unreachable
        if counter_unreachable[0] % 3 == 0:
            log(
                'OSError: {}; C_UNREACHABLE: {}'.format(
                    e, counter_unreachable), 'warn', verbose)
        counter_unreachable += 1
        sock_send = None
    # except Exception as e:
    #     log('ERROR en sendto: {} [{}]'.format(e, e.__class__), 'err', verbose)
    #     sock_send = _get_broadcast_socket()
    #     sock_send.sendto(encrypted_msg_b, (_UDP_IP, UDP_PORT))
    log('SENDED: {}'.format(msg), 'debug', verbose, False)
    return sock_send
Example #10
0
def receiver_msg_generator(verbose=True, n_msgs=None, port=None, codec=None):
    """
    Generador de mensajes en el receptor de la emisión en la broadcast IP. Recibe los mensajes y los desencripta.
    También devuelve los tiempos implicados en la recepción (~ el ∆T entre mensajes) y el proceso de desencriptado.
    :param verbose: :bool: Imprime Broadcast IP & PORT.
    :param n_msgs: :int: # de mensajes a recibir (ilimitados por defecto).
    :param port: :int: # de puerto de escucha.
    :param codec: :Fernet obj: Fernet object for decrypting msgs.
    :yield: msg, ∆T_msg, ∆T_decryp
    """
    if port is None:
        port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)
    if codec is None:
        codec = get_codec(get_encryption_key())

    sock, counter = None, 0
    udp_ip = _UDP_IP
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            sock.bind((udp_ip, port))
        except OSError as e:
            log('OSError --> {}. IP={}, PORT={}'.format(e, udp_ip, port), 'error', verbose)
            raise KeyboardInterrupt
        log(_DESCRIPTION_IO.format(udp_ip, port), 'ok', verbose)
        while (n_msgs is None) or (counter < n_msgs):
            tic = time()
            data, addr = sock.recvfrom(1024)  # buffer size is 1024 bytes
            toc_msg = time()
            try:
                msg = codec.decrypt(data).decode()
            except InvalidToken as e:
                log('InvalidToken ERROR: {}. La clave es correcta?\n* KEY: "{}"'
                    .format(e, get_encryption_key()), 'error', verbose, True)
                break
            toc_dcry = time()
            yield msg, toc_msg - tic, toc_dcry - toc_msg
            counter += 1
        # log('Closing receiver_msg_generator socket...', 'debug', verbose, True)
    # except OSError as e:
    #     log('OSError {} en receiver_msg_generator'.format(e), 'error', verbose, True)
    except KeyboardInterrupt:
        log('KeyboardInterrupt en receiver_msg_generator', 'warn', verbose, True)
    if sock is not None:
        sock.close()
    raise StopIteration
Example #11
0
def broadcast_msg(msg, counter_unreachable, sock_send=None, codec=None, port=None, verbose=True):
    """
    Emisión de datos en modo broadcast UDP (para múltiples receptores) como mensaje de texto encriptado.
    :param msg: Cadena de texto a enviar.
    :param counter_unreachable: np.array([0, 0]) de control de emisiones incorrectas (seguidas y totales)
    :param sock_send: Socket de envío broadcast. Se devuelve para su reutilización.
    :param codec: :Fernet obj: Fernet object for encrypting msgs.
    :param port: # de puerto de retransmisión.
    :param verbose: Imprime en stout mensajes de error y de envío de datos
    :return: sock_send
    """

    def _get_broadcast_socket(verb=False):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        # sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        log(_DESCRIPTION_IO.format(_UDP_IP, port), 'ok', verb, verb)
        return sock

    if codec is None:
        codec = get_codec()
    if port is None:
        port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)
    if sock_send is None:
        sock_send = _get_broadcast_socket()
    encrypted_msg_b = codec.encrypt(msg.encode())
    try:
        sock_send.sendto(encrypted_msg_b, (_UDP_IP, port))
        counter_unreachable[0] = 0
    except OSError as e:  # [Errno 101] Network is unreachable
        if counter_unreachable[0] % 3 == 0:
            log('OSError: {}; C_UNREACHABLE: {}'.format(e, counter_unreachable), 'warn', verbose)
        counter_unreachable += 1
        sock_send = None
    # except Exception as e:
    #     log('ERROR en sendto: {} [{}]'.format(e, e.__class__), 'err', verbose)
    #     sock_send = _get_broadcast_socket()
    #     sock_send.sendto(encrypted_msg_b, (_UDP_IP, UDP_PORT))
    log('SENDED: {}'.format(msg), 'debug', verbose, False)
    return sock_send
Example #12
0
def get_encryption_key(key_file=None):
    """
    Encryption key for symmetric encryption. URL-safe base64-encoded 32-byte key

    * Get local key, or exec wizard for making one.

    :param: key_file: :str: path of the file with the encryption key
    :return: :bytes: encryption_key
    """

    if key_file is None:
        key_file = os.path.join(
            DATA_PATH,
            CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key'))
    try:
        secret_key = open(key_file).read().encode()
    except FileNotFoundError:
        print(
            '\033[0m\033[1m\033[34mCrypto KEY is missing.\033[0m Please, select one option:\n'
            '\t\033[1m1. Generate a new key.\n\t2. Input an existent key. (Copy&paste from another computer)'
        )
        selec = input('\033[34mOPTION: \033[0m\033[31m')
        if selec == '1':
            secret_key = Fernet.generate_key()
        else:
            secret_key = input('*** KEY: ').encode()
        if len(secret_key) > 10:
            print('\033[0mThe new KEY ("{}")\nwill be saved in "{}"\n'.format(
                secret_key, key_file))
            open(key_file, 'wb').write(secret_key)
        else:
            print(
                '\033[31;1mNot a valid KEY!:\n"{}". Try again... BYE!\033[0m'.
                format(secret_key))
            sys.exit(-1)
    return secret_key
Example #13
0
    def test_1_streaming(self):

        def _print_next_msg(counter, iterator):
            msg = next(iterator)
            print('** STREAM MSG {}:\n{}\n --> T_{:.3f} secs'.format(counter, msg, time() - tic))

        tic = time()
        r = self.endpoint_request('api/stream/realtime', mimetype_check='text/event-stream', status_check=200)
        print('headers={}\nmimetype={}'.format(r.headers, r.mimetype))
        assert r.is_streamed
        assert not r.stream.closed
        toc_get = time()
        print('GET took {:.4f} s'.format(toc_get - tic))

        print('En STREAMING, DATA_PATH:{}, listdir:\n{}'.format(self.DATA_PATH, os.listdir(self.DATA_PATH)))
        from enerpi.base import CONFIG
        key_file_now = os.path.join(self.DATA_PATH, CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key'))
        print('KEY_FILE_now: {}'.format(key_file_now))
        try:
            print('KEY_now: {}'.format(open(key_file_now).read()))
        except FileNotFoundError as e:
            # Problema de .secret_key ya importada!
            print(e)

        it = r.stream.response.iter_encoded()
        counter_received = 0
        for i in range(math.ceil(1.5 * self.stream_max_time)):
            try:
                _print_next_msg(i, it)
                counter_received += 1
            except StopIteration as e:
                print(e.__class__)
        self.assertGreater(counter_received, 1)
        assert not r.stream.closed
        r.stream.close()
        assert r.stream.closed
Example #14
0
        'show_switch_comments': True,
    },
    'sensors': {
        'order': 1,
        'filename': 'sensors_enerpi.json',
        'text_button':
        '<i class="fa fa-wrench" aria-hidden="true"></i> SENSORS',
        'show_switch_comments': False,
    },
    'encryption_key': {
        'order':
        2,
        'filename':
        os.path.join(
            DATA_PATH,
            CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key')),
        'text_button':
        '<i class="fa fa-user-secret" aria-hidden="true"></i> Secret Key',
        'show_switch_comments':
        False,
    },
}

TITLE_EDIT_CRYPTOKEY = 'Encryption KEY'
SUBTITLE_EDIT_CRYPTOKEY = 'KEY_FILE'
TITLE_EDIT_JS_SENSORS = 'SENSORS'
SUBTITLE_EDIT_JS_SENSORS = 'SENSORS'

OPTIONAL_PARAMS = ['PUSHBULLET_TOKEN', 'EMAIL_RECIPIENT']

Example #15
0
- Process or clear log files
- Method for appending raw data to ENERPI catalog from the ENERPI Logger
...

"""
import datetime as dt
import os
import pandas as pd
from time import time
import re
from enerpi.base import CONFIG, DATA_PATH, log, timeit, SENSORS
from enerpi.catalog import EnerpiCatalog


# Config:
INIT_LOG_MARK = CONFIG.get('ENERPI_SAMPLER', 'INIT_LOG_MARK', fallback='INIT ENERPI')
HDF_STORE = CONFIG.get('ENERPI_DATA', 'HDF_STORE')
HDF_STORE_PATH = os.path.join(DATA_PATH, HDF_STORE)

KEY = CONFIG.get('ENERPI_DATA', 'KEY', fallback='/rms')
CONFIG_CATALOG = dict(raw_file=HDF_STORE,
                      key_raw_data=KEY,
                      key_summary_data='/hours',
                      key_summary_extra='/days',
                      check_integrity=True,
                      archive_existent=False,
                      verbose=False)


def init_catalog(sensors=None, base_path=DATA_PATH, **kwargs):
    """
Example #16
0
import numpy as np
import os
import pandas as pd
from threading import Timer
from time import sleep, time
from enerpi.base import (CONFIG, SENSORS, DATA_PATH, TimerExiter, show_pi_temperature,
                         set_logging_conf, log, FILE_LOGGING, LOGGING_LEVEL)
from enerpi.database import init_catalog, save_raw_data, HDF_STORE_PATH
from enerpi.pisampler import enerpi_sampler_rms, enerpi_raw_sampler, msg_to_dict, tuple_to_dict_json
from enerpi.iobroadcast import get_codec, broadcast_msg, receiver_msg_generator
from enerpi.ledrgb import get_rgbled, led_info, led_alarm, blink_color
from enerpi.notifier import push_enerpi_error


# Disk data store
N_SAMPLES_BUFFER_DISK = CONFIG.getint('ENERPI_DATA', 'N_SAMPLES_BUFFER_DISK', fallback=60)
STORE_PERIODIC_CATALOG_SEC = CONFIG.getint('ENERPI_DATA', 'STORE_PERIODIC_CATALOG_SEC', fallback=3600)
INIT_LOG_MARK = CONFIG.get('ENERPI_SAMPLER', 'INIT_LOG_MARK', fallback='INIT')

# Variable global para controlar el estado de notificaciones vía RGB LED
LED_STATE = 0

PALETA = dict(off=(0., (0., 0., 1.)),
              standby=(250., (0., 1., 0.)),
              medium=(750., (1., .5, 0.)),
              high=(3500., (1., 0., 0.)),
              max=(4500., (1., 0., 1.)))

# Decay control
# (# of samples/s dropping a lot sometimes
#       --> y = -a * x**2. x(9:32)=1300, x(9:37)=1190, x(9:48)=995)
Example #17
0
def enerpi_logger(path_st=HDF_STORE_PATH, delta_sampling=SENSORS.delta_sec_data,
                  roll_time=SENSORS.rms_roll_window_sec, sampling_ms=SENSORS.ts_data_ms,
                  timeout=None, is_demo=False, verbose=True):
    """
    Runs ENERPI Sensor & Logger

    :param path_st:
    :param delta_sampling:
    :param roll_time:
    :param sampling_ms:
    :param timeout:
    :param is_demo:
    :param verbose:

    """
    def _save_buffer(buffer, process_save, path_store, data_catalog, v):
        if process_save is not None and process_save.is_alive():
            process_save.terminate()
        process_save = mp.Process(target=save_raw_data, args=(buffer, path_store, data_catalog, v),
                                  name='enerpi_save_buffer')
        process_save.start()
        return process_save

    global LED_STATE
    s_calc = sampling_ms if sampling_ms > 0 else 1
    n_samples_buffer = int(round(roll_time * 1000 / s_calc))
    intro = (INIT_LOG_MARK + '\n  *** Calculating RMS values with window '
                             'of {} frames (deltaT={} s, sampling: {} ms)'
             .format(n_samples_buffer, roll_time, sampling_ms))
    log(intro, 'ok')

    data_generator = enerpi_sampler_rms(
        n_samples_buffer=n_samples_buffer, delta_sampling=delta_sampling,
        min_ts_ms=sampling_ms, use_dummy_sensors=is_demo, verbose=verbose)
    LED_STATE = 0
    counter, p_save = 0, None
    led = get_rgbled(verbose=verbose)
    sock_send, counter_unreachable = None, np.array([0, 0])

    catalog = init_catalog(
        sensors=SENSORS, raw_file=path_st,
        check_integrity=True, archive_existent=True)

    l_ini = [np.nan] * SENSORS.n_cols_sampling
    l_ini[0] = dt.datetime.now()
    buffer_disk = np.array(l_ini * N_SAMPLES_BUFFER_DISK).reshape(
        N_SAMPLES_BUFFER_DISK, SENSORS.n_cols_sampling)
    tic_abs = time()

    cond_while = True if timeout is None else TimerExiter(timeout)
    codec = get_codec()
    port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)

    if n_samples_buffer is None:
        min_n_raw_samples = MIN_N_SAMPLES_ABS
    else:
        min_n_raw_samples = max(
            MIN_N_SAMPLES_ABS, int(
                MIN_N_SAMPLES_DELTA_FRACTION
                * min(MIN_N_SAMPLES_MAX_CONSIDERED, n_samples_buffer))
        )

    error_decay = {'counter_act': 0,
                   'subject': 'SAMPLING DECAY -> {}',
                   'mask': 'Sampling freq decay until {}. '
                           '# act: {}. # Unreach. Net: {}',
                   'last_error_decay': None}
    # Loop
    try:
        while cond_while:
            # Recibe sample del generador de datos
            data = next(data_generator)

            # Broadcast mensaje
            sock_send = broadcast_msg(
                tuple_to_dict_json(data), counter_unreachable,
                sock_send=sock_send, verbose=verbose, codec=codec, port=port)
            # Almacenamiento en buffer
            for i in range(len(data)):
                buffer_disk[counter, i] = data[i]
            counter += 1

            if (data[-2] < MIN_N_SAMPLES_ABS) \
                    or (data[-2] < min_n_raw_samples) and (LED_STATE == 0):
                # Sampling decay problem --> red blink (ERROR SAMPLING)
                _set_led_state_alarm(
                    led, time_blinking=10, timeout=10,
                    time_on=.1, alarm_type='error')
                error_decay['counter_act'] += 1
                if ((error_decay['counter_act'] > 5) and
                        ((error_decay['last_error_decay'] is None)
                         or (time() - error_decay['last_error_decay'] > 300))):
                    # Decay error update
                    error_decay['last_error_decay'] = time()
                    msg = error_decay['mask'].format(
                        data[-2], error_decay['counter_act'],
                        counter_unreachable)
                    _ = push_enerpi_error(
                        error_decay['subject'].format(data[-2]), msg)
                    error_decay['counter_act'] = 0
            elif (counter_unreachable[0] > 1) and (LED_STATE == 0):
                # Unreachable network (wifi issues) -->   2x yellow blink (ERROR NETWORK)
                _set_led_state_alarm(led, time_blinking=2, time_on=.2, timeout=2, alarm_type='warning')
            elif (LED_STATE == 0) and (counter % 2 == 0):
                # Normal operation: blink with color as function of main_rms value in W --> LED Blink every 2 sec
                _set_led_blink_rgbled(led, data[1])
            elif LED_STATE == 0:
                # Reset decay error with normal operation
                error_decay['counter_act'] = 0

            # Almacenamiento en disco del buffer
            if counter >= N_SAMPLES_BUFFER_DISK:
                # Compactado de HDF Store cada STORE_PERIODIC_CATALOG_SEC
                w_compact = time() - tic_abs >= STORE_PERIODIC_CATALOG_SEC
                if w_compact:
                    p_save = _save_buffer(buffer_disk, p_save, path_st, catalog, verbose)
                else:
                    p_save = _save_buffer(buffer_disk, p_save, path_st, None, verbose)
                if w_compact:
                    tic_abs = time()
                # 2x blink azul en grabación
                _set_led_state_info(led, n_blinks=2)
                buffer_disk[:, 1] = np.nan
                counter = 0
    except StopIteration:
        log('Exiting SENDER because StopIteration', 'warn', verbose)
    except KeyboardInterrupt:
        # log('Interrumpting SENDER with KeyboardInterrupt', 'warn', verbose)
        pass
    [obj.close() for obj in [sock_send, led] if obj is not None]
    if is_demo:
        log('Exiting SENDER_RANDOM...', 'info', verbose)
    else:
        log('Exiting ENERPI_LOGGER...', 'info', verbose)
Example #18
0
# -*- coding: utf-8 -*-
"""
ENERPI - Broadcast receiver & emitter

"""
from cryptography.fernet import Fernet, InvalidToken
from binascii import Error
import os
import socket
import sys
from time import time
from enerpi.base import DATA_PATH, CONFIG, log

# LAN broadcasting
_UDP_IP = CONFIG.get('BROADCAST', 'UDP_IP', fallback="192.168.1.255")
_DESCRIPTION_IO = "\tSENDER - RECEIVER vía UDP. Broadcast IP: {}, PORT: {}"


def get_encryption_key(key_file=None):
    """
    Encryption key for symmetric encryption. URL-safe base64-encoded 32-byte key

    * Get local key, or exec wizard for making one.

    :param: key_file: :str: path of the file with the encryption key
    :return: :bytes: encryption_key
    """

    if key_file is None:
        key_file = os.path.join(
            DATA_PATH,
Example #19
0
# -*- coding: utf-8 -*-
"""
ENERPI - RGB LED control methods

"""
from enerpi.base import CONFIG, log, CONFIG_FILENAME
import datetime as dt
# dateutil included in python-dateutil
# noinspection PyPackageRequirements
from dateutil.parser import parse


# PINOUT RGB_LED
WITH_RGBLED = CONFIG.getboolean('RGBLED', 'WITH_RGBLED', fallback=False)
PIN_R = CONFIG.getint('RGBLED', 'PIN_R', fallback=19)
PIN_G = CONFIG.getint('RGBLED', 'PIN_G', fallback=20)
PIN_B = CONFIG.getint('RGBLED', 'PIN_B', fallback=16)

# Horario de funcionamiento del RGB LED
LED_TIME_ON = CONFIG.get('RGBLED', 'TIME_ON', fallback=None)
LED_TIME_OFF = CONFIG.get('RGBLED', 'TIME_OFF', fallback=None)
if LED_TIME_ON is not None:
    LED_TIME_ON = parse(LED_TIME_ON)
if LED_TIME_OFF is not None:
    LED_TIME_OFF = parse(LED_TIME_OFF)


def _use_led():
    if LED_TIME_ON and LED_TIME_OFF:
        if LED_TIME_ON.time() < dt.datetime.now().time() < LED_TIME_OFF.time():
            return True
Example #20
0
# -*- coding: utf-8 -*-
"""
ENERPI - RGB LED control methods

"""
from enerpi.base import CONFIG, log, CONFIG_FILENAME
import datetime as dt
# dateutil included in python-dateutil
# noinspection PyPackageRequirements
from dateutil.parser import parse

# PINOUT RGB_LED
WITH_RGBLED = CONFIG.getboolean('RGBLED', 'WITH_RGBLED', fallback=False)
PIN_R = CONFIG.getint('RGBLED', 'PIN_R', fallback=19)
PIN_G = CONFIG.getint('RGBLED', 'PIN_G', fallback=20)
PIN_B = CONFIG.getint('RGBLED', 'PIN_B', fallback=16)

# Horario de funcionamiento del RGB LED
LED_TIME_ON = CONFIG.get('RGBLED', 'TIME_ON', fallback=None)
LED_TIME_OFF = CONFIG.get('RGBLED', 'TIME_OFF', fallback=None)
if LED_TIME_ON is not None:
    LED_TIME_ON = parse(LED_TIME_ON)
if LED_TIME_OFF is not None:
    LED_TIME_OFF = parse(LED_TIME_OFF)


def _use_led():
    if LED_TIME_ON and LED_TIME_OFF:
        if LED_TIME_ON.time() < dt.datetime.now().time() < LED_TIME_OFF.time():
            return True
        return False
Example #21
0
# -*- coding: utf-8 -*-
"""
ENERPI - Broadcast receiver & emitter

"""
from cryptography.fernet import Fernet, InvalidToken
from binascii import Error
import os
import socket
import sys
from time import time
from enerpi.base import DATA_PATH, CONFIG, log


# LAN broadcasting
_UDP_IP = CONFIG.get('BROADCAST', 'UDP_IP', fallback="192.168.1.255")
_DESCRIPTION_IO = "\tSENDER - RECEIVER vía UDP. Broadcast IP: {}, PORT: {}"


def get_encryption_key(key_file=None):
    """
    Encryption key for symmetric encryption. URL-safe base64-encoded 32-byte key

    * Get local key, or exec wizard for making one.

    :param: key_file: :str: path of the file with the encryption key
    :return: :bytes: encryption_key
    """

    if key_file is None:
        key_file = os.path.join(DATA_PATH, CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key'))
Example #22
0
ENERPI_CONFIG_FILES = {
    'config': {
        'order': 0,
        'filename': 'config_enerpi.ini',
        'text_button': '<i class="fa fa-check-square-o" aria-hidden="true"></i> ENERPI config',
        'show_switch_comments': True,
    },
    'sensors': {
        'order': 1,
        'filename': 'sensors_enerpi.json',
        'text_button': '<i class="fa fa-wrench" aria-hidden="true"></i> SENSORS',
        'show_switch_comments': False,
    },
    'encryption_key': {
        'order': 2,
        'filename': os.path.join(DATA_PATH, CONFIG.get('BROADCAST', 'KEY_FILE', fallback='.secret_key')),
        'text_button': '<i class="fa fa-user-secret" aria-hidden="true"></i> Secret Key',
        'show_switch_comments': False,
    },
}

TITLE_EDIT_CRYPTOKEY = 'Encryption KEY'
SUBTITLE_EDIT_CRYPTOKEY = 'KEY_FILE'
TITLE_EDIT_JS_SENSORS = 'SENSORS'
SUBTITLE_EDIT_JS_SENSORS = 'SENSORS'

OPTIONAL_PARAMS = ['PUSHBULLET_TOKEN', 'EMAIL_RECIPIENT']


def _web_edit_enerpi_config_ini(lines_ini_file):
    """
Example #23
0
"""
ENERPIWEB - CLI methods:

- Install configuration & CRON task for web resources generation
- Uninstall CRON task
- Run Flask server

"""
import argparse
import os
import sys
from enerpi.base import BASE_PATH, DATA_PATH, CONFIG, log, check_resource_files, NGINX_CONFIG_FILE, UWSGI_CONFIG_FILE
from enerpi.prettyprinting import print_secc, print_cyan, print_red, print_magenta


FLASK_WEBSERVER_PORT = CONFIG.getint('ENERPI_WEBSERVER', 'FLASK_WEBSERVER_PORT', fallback=7777)
PERIOD_MINUTES_RSC_GEN = CONFIG.getint('ENERPI_WEBSERVER', 'RSC_GEN_EVERY_MINUTES', fallback=15)
USER_SERVER = CONFIG.get('ENERPI_WEBSERVER', 'USER_SERVER', fallback='www-data')
basedir = os.path.abspath(os.path.dirname(__file__))


def make_cron_command_task_periodic_rscgen():
    """
    CRON task for generate web resources with enerpiplot.mule_rscgen.py
    Example command:
    */15 * * * * sudo -u www-data /home/pi/PYTHON/py35/bin/python
        /home/pi/PYTHON/py35/lib/python3.5/site-packages/enerpiweb/mule_rscgen.py -o

    :return: :str: cron_command
    """
    # cmd_server = '*/{period} * * * * ...'
Example #24
0
import os
import pandas as pd
from threading import Timer
from time import sleep, time
from enerpi.base import (CONFIG, SENSORS, DATA_PATH, TimerExiter,
                         show_pi_temperature, set_logging_conf, log,
                         FILE_LOGGING, LOGGING_LEVEL)
from enerpi.database import init_catalog, save_raw_data, HDF_STORE_PATH
from enerpi.pisampler import enerpi_sampler_rms, enerpi_raw_sampler, msg_to_dict, tuple_to_dict_json
from enerpi.iobroadcast import get_codec, broadcast_msg, receiver_msg_generator
from enerpi.ledrgb import get_rgbled, led_info, led_alarm, blink_color
from enerpi.notifier import push_enerpi_error

# Disk data store
N_SAMPLES_BUFFER_DISK = CONFIG.getint('ENERPI_DATA',
                                      'N_SAMPLES_BUFFER_DISK',
                                      fallback=60)
STORE_PERIODIC_CATALOG_SEC = CONFIG.getint('ENERPI_DATA',
                                           'STORE_PERIODIC_CATALOG_SEC',
                                           fallback=3600)
INIT_LOG_MARK = CONFIG.get('ENERPI_SAMPLER', 'INIT_LOG_MARK', fallback='INIT')

# Variable global para controlar el estado de notificaciones vía RGB LED
LED_STATE = 0

PALETA = dict(off=(0., (0., 0., 1.)),
              standby=(250., (0., 1., 0.)),
              medium=(750., (1., .5, 0.)),
              high=(3500., (1., 0., 0.)),
              max=(4500., (1., 0., 1.)))
Example #25
0
def enerpi_main_cli(test_mode=False):
    """
    Uso de ENERPI desde CLI

    enerpi -h para mostrar las diferentes opciones

    """
    # CLI Arguments
    args = _enerpi_arguments()
    verbose = not args.silent

    if args.version:
        return __version__

    # CONTROL LOGIC
    # Shows RPI Temps
    timer_temps = show_pi_temperature(args.temps, 3, args.timeout)

    if args.install or args.uninstall:
        from enerpi.config.crontasks import set_command_on_reboot, clear_cron_commands
        # INSTALL / UNINSTALL CRON TASKS & KEY
        cmd_logger = make_cron_command_task_daemon()
        if args.install:
            # Logging configuration
            set_logging_conf(FILE_LOGGING, LOGGING_LEVEL, True)

            log('** Installing CRON task for start logger at reboot:\n"{}"'.format(cmd_logger), 'ok', True, False)
            set_command_on_reboot(cmd_logger, verbose=verbose)
            try:
                os.chmod(DATA_PATH, 0o777)
                [os.chmod(os.path.join(base, f), 0o777)
                 for base, dirs, files in os.walk(DATA_PATH) for f in files + dirs]
            except PermissionError:
                log("Can't set 777 permissions on {0}/* files...\nDo it manually, please: 'sudo chmod 777 -R {0}'"
                    .format(DATA_PATH), 'warning', True, False)
        else:
            log('** Deleting CRON task for start logger at reboot:\n"{}"'.format(cmd_logger), 'warn', True, False)
            clear_cron_commands([cmd_logger], verbose=verbose)
    elif (args.enerpi or args.info or args.backup or args.reprocess or args.config or args.raw or
            args.last or args.clearlog or args.filter or args.plot or args.plot_tiles):
        # Init CLI
        # import matplotlib
        # matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        import pandas as pd
        pd.set_option('display.width', 200)

        # Logging configuration
        set_logging_conf(FILE_LOGGING, LOGGING_LEVEL, True)

        # Shows INI config & SENSORS
        if args.config:
            import json

            log('ENERPI Configuration (from INI file in "{}"):'
                .format(os.path.join(DATA_PATH, CONFIG_FILENAME)), 'ok', True, False)
            for s in CONFIG.sections():
                log('* Section {}:'.format(s), 'info', True, False)
                for opt in CONFIG.options(s):
                    log('{:27} -->\t{}'.format(opt.upper(), CONFIG.get(s, opt)), 'debug', True, False)
            log('*' * 80 + '\n', 'ok', True, False)
            log('\nENERPI SENSORS Config (from JSON file in "{}"):'
                .format(os.path.join(DATA_PATH, SENSORS_CONFIG_JSON_FILENAME)), 'ok', True, False)
            json_content = json.loads(open(os.path.join(DATA_PATH, SENSORS_CONFIG_JSON_FILENAME), 'r').read())
            log('\n'.join(['{}'.format(s) for s in json_content]), 'magenta', True, False)
            log('--> {}\n\n'.format(SENSORS), 'ok', True, False)
        # Delete LOG File
        if args.clearlog:
            from enerpi.database import delete_log_file

            delete_log_file(FILE_LOGGING, verbose=verbose)
        # Data Store Config
        _existe_st, path_st = _check_store_relpath(args.store)

        # Starts ENERPI Logger
        if args.enerpi:
            from enerpi.enerpimeter import enerpi_logger

            # Demo logger
            if args.demo:
                set_logging_conf(FILE_LOGGING + '_demo.log', LOGGING_LEVEL, True)
                path_st = os.path.join(DATA_PATH, 'debug_buffer_disk.h5')
            enerpi_logger(is_demo=args.demo, verbose=verbose, path_st=path_st, delta_sampling=args.delta,
                          roll_time=args.window, sampling_ms=args.ts, timeout=args.timeout)
        elif args.backup:
            from enerpi.database import init_catalog
            # Export data to CSV:
            catalog = init_catalog(sensors=SENSORS, raw_file=path_st, check_integrity=False,
                                   verbose=verbose, test_mode=test_mode)
            export_ok = catalog.export_chunk(args.backup)
            log('EXPORT OK? {}'.format(export_ok), 'ok' if export_ok else 'error', True, False)
        elif args.reprocess:
            from enerpi.database import init_catalog
            # Re-process all data in catalog
            catalog = init_catalog(sensors=SENSORS, raw_file=path_st, check_integrity=False,
                                   verbose=verbose, test_mode=test_mode)
            repro_ok = catalog.reprocess_all_data()
            log('REPROCESS OK? {}'.format(repro_ok), 'ok' if repro_ok else 'error', verbose, verbose)
        # TODO revisar config X11 + ssh -X para plot en display local
        elif args.raw:
            from enerpi.enerpimeter import enerpi_raw_data

            # Raw mode
            delta_secs = args.raw
            raw_data = enerpi_raw_data(path_st.replace('.h5', '_raw_sample.h5'), delta_secs=delta_secs,
                                       use_dummy_sensors=args.demo,
                                       roll_time=args.window, sampling_ms=args.ts, verbose=verbose)
            t0, tf = raw_data.index[0], raw_data.index[-1]
            log('Showing RAW DATA for {} seconds ({} samples, {:.2f} sps)\n** Real data: from {} to {} --> {:.2f} sps'
                .format(delta_secs, len(raw_data), len(raw_data) / delta_secs,
                        t0, tf, len(raw_data) / (tf-t0).total_seconds()), 'info', verbose, False)
            raw_data.plot(lw=.5, figsize=(16, 10))
            plt.show()
        # Shows database info
        elif args.info or args.filter or args.plot or args.plot_tiles:
            from enerpi.database import init_catalog, show_info_data

            catalog = init_catalog(sensors=SENSORS, raw_file=path_st, check_integrity=False,
                                   verbose=verbose, test_mode=test_mode)
            if args.plot_tiles:
                from enerpiplot.enerplot import gen_svg_tiles

                ok = gen_svg_tiles(IMG_TILES_BASEPATH, catalog, color=COLOR_TILES if not test_mode else (1, 0, 0))
                if ok:
                    log('SVG Tiles generated!', 'ok', verbose, True)
                else:
                    log('No generation of SVG Tiles!', 'error', verbose, True)
            else:
                data, consumption = _extract_time_slice_from_args(args.filter, args.info, catalog)

                if (args.info or args.filter) and data is not None and not data.empty:
                    show_info_data(data, consumption)
                if (args.plot and (data is not None) and not data.empty and (consumption is not None) and
                        not consumption.empty):
                    from enerpiplot.enerplot import plot_power_consumption_hourly

                    rs_data, rm_data, path_saveimg, show = _extract_plot_params_from_args(args.plot, args.plot_options)
                    mean_sensor_data = data[SENSORS.columns_sensors_mean] if SENSORS.columns_sensors_mean else None
                    log('Generate PLOT with RESAMPLE={}, ROLLING={}, show={}, path_save="{}"'
                        .format(rs_data, rm_data, show, path_saveimg), 'info', verbose, False)
                    img_name = plot_power_consumption_hourly(data[SENSORS.columns_sensors_rms],
                                                             consumption.kWh, data_mean_s=mean_sensor_data,
                                                             rs_data=rs_data, rm_data=rm_data,
                                                             show=show, path_saveimg=path_saveimg)
                    if img_name is not None:
                        log('IMAGE saved in "{}"'.format(img_name), 'ok', verbose, False)
        # Shows database info
        else:  # Shows last 10 entries
            from enerpi.database import get_ts_last_save

            last = get_ts_last_save(path_st, get_last_sample=True, verbose=verbose, n=10)
            log('Showing last 10 entries in {}:\n{}'.format(path_st, last), 'info', verbose, False)
    # Shows & extract info from LOG File
    elif args.log:
        from enerpi.database import extract_log_file

        data_log = extract_log_file(FILE_LOGGING, extract_temps=True, verbose=verbose)
        try:
            df_temps = data_log[data_log.temp.notnull()].drop(['tipo', 'msg', 'debug_send'], axis=1).dropna(axis=1)
            if len(set(df_temps['exec'])) == 1:
                df_temps = df_temps.drop(['exec'], axis=1)
            path_csv = os.path.join(DATA_PATH, 'debug_rpitemps.csv')
            if not df_temps.empty:
                df_temps.to_csv(path_csv)
                print('*** Saved temperature data extracted from LOG in {}'.format(path_csv))
        except AttributeError:
            print('No se encuentran datos de Tª de RPI en el LOG')
    # Demo sender
    elif args.demo:
        from enerpi.enerpimeter import enerpi_logger

        set_logging_conf(FILE_LOGGING + '_demo.log', LOGGING_LEVEL, True)
        path_st = os.path.join(DATA_PATH, 'debug_buffer_disk.h5')
        enerpi_logger(is_demo=True, verbose=verbose, path_st=path_st, delta_sampling=args.delta,
                      roll_time=args.window, sampling_ms=args.ts, timeout=args.timeout)
    # Receiver
    else:  # elif args.receive:
        from enerpi.enerpimeter import receiver

        log('{}\n   {}'.format(PRETTY_NAME, DESCRIPTION), 'ok', verbose, False)
        receiver(verbose=verbose, timeout=args.timeout, port=args.port)
    if timer_temps is not None:
        log('Stopping RPI TEMPS sensing...', 'debug', True)
        timer_temps.cancel()
    log('Exiting from ENERPI CLI...', 'debug', True)
    if not test_mode:
        sys.exit(0)
Example #26
0
"""
ENERPI - CLI methods & argument parser

"""
import datetime as dt
import os
import re
import sys
from enerpi import PRETTY_NAME, DESCRIPTION, __version__
from enerpi.base import (IMG_TILES_BASEPATH, DATA_PATH, CONFIG, SENSORS, CONFIG_FILENAME, SENSORS_CONFIG_JSON_FILENAME,
                         FILE_LOGGING, LOGGING_LEVEL, set_logging_conf, log, show_pi_temperature,
                         DEFAULT_IMG_MASK, COLOR_TILES)


# Config:
UDP_PORT = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)
HDF_STORE = CONFIG.get('ENERPI_DATA', 'HDF_STORE')


def _enerpi_arguments():
    """
    CLI Parser
    """
    import argparse

    p = argparse.ArgumentParser(description="\033[1m\033[5m\033[32m{}\033[0m\n{}\n\n".format(PRETTY_NAME, DESCRIPTION),
                                epilog='\033[34m\n*** By default, ENERPI starts as receiver (-r) ***\n' +
                                       '\033[0m', formatter_class=argparse.RawTextHelpFormatter)
    g_m = p.add_argument_group(title='☆  \033[1m\033[4mENERPI Working Mode\033[24m',
                               description='→  Choose working mode between RECEIVER / SENDER')
    g_m.add_argument('-e', '--enerpi', action='store_true', help='⚡  SET ENERPI LOGGER & BROADCAST MODE')
Example #27
0
def enerpi_logger(path_st=HDF_STORE_PATH,
                  delta_sampling=SENSORS.delta_sec_data,
                  roll_time=SENSORS.rms_roll_window_sec,
                  sampling_ms=SENSORS.ts_data_ms,
                  timeout=None,
                  is_demo=False,
                  verbose=True):
    """
    Runs ENERPI Sensor & Logger

    :param path_st:
    :param delta_sampling:
    :param roll_time:
    :param sampling_ms:
    :param timeout:
    :param is_demo:
    :param verbose:

    """
    def _save_buffer(buffer, process_save, path_store, data_catalog, v):
        if process_save is not None and process_save.is_alive():
            process_save.terminate()
        process_save = mp.Process(target=save_raw_data,
                                  args=(buffer, path_store, data_catalog, v),
                                  name='enerpi_save_buffer')
        process_save.start()
        return process_save

    global LED_STATE
    s_calc = sampling_ms if sampling_ms > 0 else 1
    n_samples_buffer = int(round(roll_time * 1000 / s_calc))
    intro = (INIT_LOG_MARK + '\n  *** Calculating RMS values with window '
             'of {} frames (deltaT={} s, sampling: {} ms)'.format(
                 n_samples_buffer, roll_time, sampling_ms))
    log(intro, 'ok')

    data_generator = enerpi_sampler_rms(n_samples_buffer=n_samples_buffer,
                                        delta_sampling=delta_sampling,
                                        min_ts_ms=sampling_ms,
                                        use_dummy_sensors=is_demo,
                                        verbose=verbose)
    LED_STATE = 0
    counter, p_save = 0, None
    led = get_rgbled(verbose=verbose)
    sock_send, counter_unreachable = None, np.array([0, 0])

    catalog = init_catalog(sensors=SENSORS,
                           raw_file=path_st,
                           check_integrity=True,
                           archive_existent=True)

    l_ini = [np.nan] * SENSORS.n_cols_sampling
    l_ini[0] = dt.datetime.now()
    buffer_disk = np.array(l_ini * N_SAMPLES_BUFFER_DISK).reshape(
        N_SAMPLES_BUFFER_DISK, SENSORS.n_cols_sampling)
    tic_abs = time()

    cond_while = True if timeout is None else TimerExiter(timeout)
    codec = get_codec()
    port = CONFIG.getint('BROADCAST', 'UDP_PORT', fallback=57775)

    if n_samples_buffer is None:
        min_n_raw_samples = MIN_N_SAMPLES_ABS
    else:
        min_n_raw_samples = max(
            MIN_N_SAMPLES_ABS,
            int(MIN_N_SAMPLES_DELTA_FRACTION *
                min(MIN_N_SAMPLES_MAX_CONSIDERED, n_samples_buffer)))

    error_decay = {
        'counter_act': 0,
        'subject': 'SAMPLING DECAY -> {}',
        'mask': 'Sampling freq decay until {}. '
        '# act: {}. # Unreach. Net: {}',
        'last_error_decay': None
    }
    # Loop
    try:
        while cond_while:
            # Recibe sample del generador de datos
            data = next(data_generator)

            # Broadcast mensaje
            sock_send = broadcast_msg(tuple_to_dict_json(data),
                                      counter_unreachable,
                                      sock_send=sock_send,
                                      verbose=verbose,
                                      codec=codec,
                                      port=port)
            # Almacenamiento en buffer
            for i in range(len(data)):
                buffer_disk[counter, i] = data[i]
            counter += 1

            if (data[-2] < MIN_N_SAMPLES_ABS) \
                    or (data[-2] < min_n_raw_samples) and (LED_STATE == 0):
                # Sampling decay problem --> red blink (ERROR SAMPLING)
                _set_led_state_alarm(led,
                                     time_blinking=10,
                                     timeout=10,
                                     time_on=.1,
                                     alarm_type='error')
                error_decay['counter_act'] += 1
                if ((error_decay['counter_act'] > 5) and
                    ((error_decay['last_error_decay'] is None) or
                     (time() - error_decay['last_error_decay'] > 300))):
                    # Decay error update
                    error_decay['last_error_decay'] = time()
                    msg = error_decay['mask'].format(
                        data[-2], error_decay['counter_act'],
                        counter_unreachable)
                    _ = push_enerpi_error(
                        error_decay['subject'].format(data[-2]), msg)
                    error_decay['counter_act'] = 0
            elif (counter_unreachable[0] > 1) and (LED_STATE == 0):
                # Unreachable network (wifi issues) -->   2x yellow blink (ERROR NETWORK)
                _set_led_state_alarm(led,
                                     time_blinking=2,
                                     time_on=.2,
                                     timeout=2,
                                     alarm_type='warning')
            elif (LED_STATE == 0) and (counter % 2 == 0):
                # Normal operation: blink with color as function of main_rms value in W --> LED Blink every 2 sec
                _set_led_blink_rgbled(led, data[1])
            elif LED_STATE == 0:
                # Reset decay error with normal operation
                error_decay['counter_act'] = 0

            # Almacenamiento en disco del buffer
            if counter >= N_SAMPLES_BUFFER_DISK:
                # Compactado de HDF Store cada STORE_PERIODIC_CATALOG_SEC
                w_compact = time() - tic_abs >= STORE_PERIODIC_CATALOG_SEC
                if w_compact:
                    p_save = _save_buffer(buffer_disk, p_save, path_st,
                                          catalog, verbose)
                else:
                    p_save = _save_buffer(buffer_disk, p_save, path_st, None,
                                          verbose)
                if w_compact:
                    tic_abs = time()
                # 2x blink azul en grabación
                _set_led_state_info(led, n_blinks=2)
                buffer_disk[:, 1] = np.nan
                counter = 0
    except StopIteration:
        log('Exiting SENDER because StopIteration', 'warn', verbose)
    except KeyboardInterrupt:
        # log('Interrumpting SENDER with KeyboardInterrupt', 'warn', verbose)
        pass
    [obj.close() for obj in [sock_send, led] if obj is not None]
    if is_demo:
        log('Exiting SENDER_RANDOM...', 'info', verbose)
    else:
        log('Exiting ENERPI_LOGGER...', 'info', verbose)
Example #28
0
from flask_autodoc import Autodoc
from flask_mail import Mail
from werkzeug.contrib.fixers import ProxyFix
from werkzeug.routing import Rule
import jinja2
import os
# noinspection PyUnresolvedReferences
from enerpi import __version__
from enerpi.base import (CONFIG, DATA_PATH, check_resource_files,
                         GMAIL_ACCOUNT, GMAIL_APP_PASSWORD)
from enerpi.api import get_encryption_key


basedir = os.path.abspath(os.path.dirname(__file__))
STATIC_PATH = os.path.join(
    DATA_PATH, CONFIG.get('ENERPI_WEBSERVER', 'STATIC_PATH', fallback='WWW'))
LOGGING_LEVEL_SERVER = CONFIG.get(
    'ENERPI_WEBSERVER', 'LOGGING_LEVEL_WEB', fallback='DEBUG')
SERVER_FILE_LOGGING = os.path.join(
    STATIC_PATH, CONFIG.get(
        'ENERPI_WEBSERVER', 'FILE_LOGGING_WEB', fallback='enerpiweb.log'))
PREFIX_WEB = CONFIG.get('ENERPI_WEBSERVER', 'PREFIX_WEB', fallback='/enerpi')
BASECOLOR = '#{}'.format(
    CONFIG.get('ENERPI_WEBSERVER', 'BASECOLOR_HEX', fallback='0CBB43'))
check_resource_files(
    STATIC_PATH, os.path.join(basedir, 'static'), verbose=False)

# WITH_WEB = CONFIG.getboolean('ENERPI_WEBSERVER', 'WITH_WEBSERVER',
# fallback=True)
WITH_ML_SUBSYSTEM = CONFIG.getboolean('ENERPI_WEBSERVER', 'WITH_ML',
                                      fallback=False)
Example #29
0
"""
ENERPIWEB - CLI methods:

- Install configuration & CRON task for web resources generation
- Uninstall CRON task
- Run Flask server

"""
import argparse
import os
import sys
from enerpi.base import BASE_PATH, DATA_PATH, CONFIG, log, check_resource_files, NGINX_CONFIG_FILE, UWSGI_CONFIG_FILE
from enerpi.prettyprinting import print_secc, print_cyan, print_red, print_magenta

FLASK_WEBSERVER_PORT = CONFIG.getint('ENERPI_WEBSERVER',
                                     'FLASK_WEBSERVER_PORT',
                                     fallback=7777)
PERIOD_MINUTES_RSC_GEN = CONFIG.getint('ENERPI_WEBSERVER',
                                       'RSC_GEN_EVERY_MINUTES',
                                       fallback=15)
USER_SERVER = CONFIG.get('ENERPI_WEBSERVER',
                         'USER_SERVER',
                         fallback='www-data')
basedir = os.path.abspath(os.path.dirname(__file__))


def make_cron_command_task_periodic_rscgen():
    """
    CRON task for generate web resources with enerpiplot.mule_rscgen.py
    Example command:
    */15 * * * * sudo -u www-data /home/pi/PYTHON/py35/bin/python
Example #30
0
from flask import Flask
from flask_autodoc import Autodoc
from flask_mail import Mail
from werkzeug.contrib.fixers import ProxyFix
from werkzeug.routing import Rule
import jinja2
import os
# noinspection PyUnresolvedReferences
from enerpi import __version__
from enerpi.base import (CONFIG, DATA_PATH, check_resource_files,
                         GMAIL_ACCOUNT, GMAIL_APP_PASSWORD)
from enerpi.api import get_encryption_key

basedir = os.path.abspath(os.path.dirname(__file__))
STATIC_PATH = os.path.join(
    DATA_PATH, CONFIG.get('ENERPI_WEBSERVER', 'STATIC_PATH', fallback='WWW'))
LOGGING_LEVEL_SERVER = CONFIG.get('ENERPI_WEBSERVER',
                                  'LOGGING_LEVEL_WEB',
                                  fallback='DEBUG')
SERVER_FILE_LOGGING = os.path.join(
    STATIC_PATH,
    CONFIG.get('ENERPI_WEBSERVER',
               'FILE_LOGGING_WEB',
               fallback='enerpiweb.log'))
PREFIX_WEB = CONFIG.get('ENERPI_WEBSERVER', 'PREFIX_WEB', fallback='/enerpi')
BASECOLOR = '#{}'.format(
    CONFIG.get('ENERPI_WEBSERVER', 'BASECOLOR_HEX', fallback='0CBB43'))
check_resource_files(STATIC_PATH,
                     os.path.join(basedir, 'static'),
                     verbose=False)