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 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 #3
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 #4
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 #5
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 #6
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 #7
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 #8
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 #9
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 #10
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 #11
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 #12
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 #13
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 #14
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)