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()
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
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
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
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
""" 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
""" 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} * * * * ...'
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)
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.)))
# -*- 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
""" 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')
# -*- 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
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)
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)