def init_config_env(env_name, default_names=['config.cnf']): """ Creates a new ConfigParser instance and reads the file given by an Environmental Variable. If variable does not exist a default value will be used. :param str env_name: Name of Environmental Variable :param list of str default_names: Default Name (default: 'config.cnf') :return ConfigParser: """ if env_name in environ: return init_config(environ[env_name]) else: c = None for default_name in default_names: try: c = init_config(default_name) return c except ConfigFileNotFoundError: log('Could not find {} ...'.format(default_name)) if not c: log('Failed to load Configuration File!') raise ConfigFileNotFoundError('Failed to load Configuration File!') else: # This will probably never happen... return c
def _set_accuracy(self, val_x, val_y, mode): try: f_val_x = float(val_x) f_val_y = float(val_y) i_val_m = int(float(mode)) if f_val_x < 0 or f_val_y < 0: # No Data self._gpsStatusIcon.image = IMAGES[IMAGE_GPSSAT_OFF] self._accuracyLabel.settext('---') else: if i_val_m <= 1 or i_val_m > 3: # No Fix / Invalid Data self._gpsStatusIcon.image = IMAGES[IMAGE_GPSSAT_ERROR] self._accuracyLabel.settext('FIX') else: fix_accuracy = (f_val_x + f_val_y) / 2 if i_val_m == 2: # 2D FIX self._gpsStatusIcon.image = IMAGES[IMAGE_GPSSAT_WARN] elif i_val_m == 3: # 3D Fix self._gpsStatusIcon.image = IMAGES[IMAGE_GPSSAT_OK] self._accuracyLabel.settext('{:>3.0f}'.format(min(fix_accuracy, 999))) except (ValueError, TypeError): log('Failed to parse EPX, EPY or MODE: {} / {} / {}'.format(val_x, val_y, mode)) self._gpsStatusIcon.image = IMAGES[IMAGE_GPSSAT_OFF] self._accuracyLabel.settext('ERR')
def get_image(self, image_path): if image_path not in self.image_store: log("Image \"{}\" not loaded! Load image before use!".format( image_path)) return None else: return self.image_store[image_path]
def stop_safe(self, timeout=5): try: self.stop(timeout) return True except ThreadStopTimeoutError: log("Stopping {} timed out after {} seconds!".format( self.__class__.__name__, timeout)) return False
def _execute_command(self, command, params=None): if command in self._command_implementation: fun = self._command_implementation[command] if params: fun(params) else: fun() else: log("No function found for Redis Command {}!".format(command))
def __init__(self, type, val=None): """ :param str type: OBD PID :param str val: (optional) value received to parse """ log("Unknown or unimplemented OBD PID {} (Value was: {})".format( type, val)) self.type = type self.val = val
def delete_alive_key(r): """ :param Redis r: """ try: log("Deleting Alive Key ...") r.delete(MpdDataRedisKeys.KEY_ALIVE) finally: pass
def _set_longitude(self, val): try: f_val = float(val) if isnan(f_val) or (f_val == -360): self._longitudeLabel.settext('---.--------- -') else: self._longitudeLabel.settext('{:>13.9f} {}'.format(abs(f_val), 'W' if val < 0 else 'E')) except (ValueError, TypeError): log('Longitude given could not be converted to float: {}'.format(val)) self._longitudeLabel.settext('---.--------- -')
def shutdown(self): try: if self.active_window: try: self.active_window.destroy() finally: pass self._fetcher.stop_safe() self._predis_fetcher.stop_safe() log("Shutting down CarPiUIApp ...") self.destroy() finally: return
def init_config(filepath): """ Creates a new ConfigParser instance and reads the given file :param str filepath: Configuration File's Path :return ConfigParser: """ log('Reading Config File {} ...'.format(filepath)) config = ConfigParser() try: config.readfp(open(filepath)) except IOError: raise ConfigFileNotFoundError init_logging_from_config(config) return config
def _set_speed(self, val, imperial=False): try: f_val = float(val) if isnan(f_val) or (val == -1): self._speedLabel.settext(' 0') self._speedGraph.add_data_point(0) else: self._speedLabel.settext('{:>3.0f}'.format(f_val)) self._speedGraph.add_data_point(f_val) except (ValueError, TypeError): log('Speed given could not be converted to float: {}'.format(val)) self._speedLabel.settext(' 0') self._speedGraph.add_data_point(0) # self._speedGraph.add_data_point(datetime.now().second) self._speedUnitLabel.settext(' mph' if imperial else 'km/h')
def parse_value(type, val): """ Parses a given OBD value of a given type (PID) and returns the parsed value. If the PID is unknown / not implemented a PIDParserUnknownError will be raised including the type which was unknown :param type: :param val: :return: """ if type in PARSER_MAP: prep_val = prepare_value(val) out = PARSER_MAP[type](prep_val) log('For {} entered {}, got {} out'.format(type, prep_val, out)) return out else: raise ObdPidParserUnknownError(type, val)
def init_pygame(config): """ :param ConfigParser config: :return: """ log('Initializing PyGame ...') init_passed, init_failed = pygame.init() log('PyGame initialized using Ver. {}, {} modules loaded, {} modules failed' .format(pygame.ver, init_passed, init_failed)) mouse_visible = False if config.has_option(UI_CONFIG_SECTION, UI_CONFIG_KEY_SHOW_MOUSE): mouse_visible = config.getboolean(UI_CONFIG_SECTION, UI_CONFIG_KEY_SHOW_MOUSE) pygame.mouse.set_visible(mouse_visible) pygame.display.set_mode( (config.getint(UI_CONFIG_SECTION, UI_CONFIG_KEY_RES_WIDTH), config.getint(UI_CONFIG_SECTION, UI_CONFIG_KEY_RES_HEIGHT)))
def init_io(config): """ :param ConfigParser config: :return: """ log("Configuring PyGame IO ...") if ENV_OUTPUT not in environ: if config.has_option(IO_CONFIG_SECTION, IO_CONFIG_KEY_OUTPUT_DEVICE): environ[ENV_OUTPUT] = config.get(IO_CONFIG_SECTION, IO_CONFIG_KEY_OUTPUT_DEVICE) if ENV_MOUSE_DEVICE not in environ: if config.has_option(IO_CONFIG_SECTION, IO_CONFIG_KEY_MOUSE_DEVICE): environ[ENV_MOUSE_DEVICE] = config.get(IO_CONFIG_SECTION, IO_CONFIG_KEY_MOUSE_DEVICE) if ENV_MOUSE_DRIVER not in environ: if config.has_option(IO_CONFIG_SECTION, IO_CONFIG_KEY_MOUSE_DRIVER): environ[ENV_MOUSE_DRIVER] = config.get(IO_CONFIG_SECTION, IO_CONFIG_KEY_MOUSE_DRIVER)
def prepare_value(v): """ :param str v: :return str: """ log('Preparing value {}'.format(v)) a = v.split('|') if len(a) >= 2 and a[1] != '>': log('Returning {} for {}'.format(a[1], v)) return a[1] else: log('Returning NONE for {}'.format(v)) return None
def load_image(path, convert_alpha=True): image = None try: log('Loading Image {} ...'.format(path)) with open(path) as f: image = pygame.image.load(f) # type: pygame.Surface if image and convert_alpha: image = image.convert_alpha(image) except IOError: log('Could not load image {}!'.format(path)) except pygame.error as err: log('PyGame did a bad while loading "{}": {}'.format( path, err.message)) return image
def _do(self): try: self._fetch_data() self._retries = RedisBackgroundFetcher.RETRIES except (exceptions.ConnectionError, exceptions.TimeoutError): if self._retries == 0: log("Failed to reconnect to Redis after {} retries!".format( RedisBackgroundFetcher.RETRIES)) raise else: log("Connection to Redis lost, skipping and trying again in {} seconds ({} more times) ..." .format(RedisBackgroundFetcher.RETRY_INTERVAL, self._retries)) self._retries -= 1 sleep(RedisBackgroundFetcher.RETRY_INTERVAL) except SystemExit: log("SystemExit has been requested, stopping Fetcher Thread ...") self._running = False
def get_redis(config): """ Returns the default Redis connection :param ConfigParser config: :return Redis: """ global RCONFIG_VALUE_EXPIRE try: RCONFIG_VALUE_EXPIRE = config.getint(RCONFIG_SECTION, RCONFIG_KEY_EXPIRE) log("The Redis values will expire after {} seconds.".format( RCONFIG_VALUE_EXPIRE)) except NoOptionError: log("The Redis values will not expire.") RCONFIG_VALUE_EXPIRE = None except ValueError: log("The provided default Expire value is invalid! No expiration will be set." ) RCONFIG_VALUE_EXPIRE = None return _get_redis(config, RCONFIG_SECTION)
def init_config_env(env_name, default_names=['config.cnf']): """ Creates a new ConfigParser instance and reads the file given by an Environmental Variable. If variable does not exist a default value will be used. :param str env_name: Name of Environmental Variable :param list of str default_names: Default Name (default: 'config.cnf') :return ConfigParser: """ if env_name in environ: return init_config(environ[env_name]) else: c = None for default_name in default_names: try: c = init_config(default_name) return c except ConfigFileNotFoundError: log('Could not find {} ...'.format(default_name)) if not c: log('Failed to load Configuration File!') raise ConfigFileNotFoundError('Failed to load Configuration File!') else: # This will probably never happen... return c if __name__ == "__main__": log("This script is not intended to be run standalone!")
pass if __name__ == "__main__": EXIT_CODE = EXIT_CODES['OK'] CONFIG = init_config_env('CARPI_NETD_CONF', ['mpd-daemon.conf', '/etc/carpi/mpd-daemon.conf']) boot_print(APP_NAME) CONFIG_DATAPOLLER_INTERVAL = CONFIG.getfloat('DataPoller', 'interval') / 1000 CONFIG_CONTROLLER_INTERVAL = CONFIG.getfloat('Controller', 'interval') / 1000 log("Connecting to MPD ...") MPD_DATA_THREAD = MpdDataPoller(CONFIG, CONFIG_DATAPOLLER_INTERVAL) MPD_DATA_THREAD.start() log("Initializing Redis Connection ...") R = get_redis(CONFIG) log("Initializing Control Thread ...") MPD_CONTROL = MpdControlThread(CONFIG, R, CONFIG_CONTROLLER_INTERVAL) MPD_CONTROL.start() try: log("MPD Data & Control Daemon is running ...") while True: if not MPD_DATA_THREAD.isAlive() or not MPD_CONTROL.isAlive(): raise ConnectionError()
from sys import exit APP_NAME = path.basename(__file__) SYNC_SETTINGS = [PersistentGpsRedisKeys.KEY_TRIP_A_RECORDING] EXIT_CODE = EXIT_CODES['OK'] if __name__ == "__main__": APP = None # type: CarPiUIApp try: CONFIG = init_config_env('CARPI_UI_CONFIG', ['ui.conf', '/etc/carpi/ui.conf']) boot_print(APP_NAME) log("Initializing Data Source ...") R = get_redis(CONFIG) RP = get_persistent_redis(CONFIG) log("Synchronizing values ...") for key in SYNC_SETTINGS: load_synced_value(R, RP, key) log("Configuring UI ...") init_io(CONFIG) init_pygame(CONFIG) APP = CarPiUIApp( rect=(CONFIG.getint(UI_CONFIG_SECTION, UI_CONFIG_KEY_RES_WIDTH), CONFIG.getint(UI_CONFIG_SECTION, UI_CONFIG_KEY_RES_HEIGHT) - 21),
# }) if __name__ == "__main__": EXIT_CODE = EXIT_CODES['OK'] CONFIG = init_config_env('CARPI_GPSD_CONF', ['gps-daemon.conf', '/etc/carpi/gps-daemon.conf']) boot_print(APP_NAME) CONFIG_DATAPOLLER_INTERVAL = CONFIG.getfloat('DataPoller', 'interval') / 1000 CONFIG_RECORD_ODO = CONFIG.getboolean('ODO_Recording', 'enabled') CONFIG_LOCATION_POLLER_INTERVAL = CONFIG.getfloat( 'DataPoller', 'location_polling') / 1000 log("Initializing GPS ...") GPS_POLLER = GpsPoller() GPS_POLLER.start() log("Initializing Redis Connection ...") R = get_redis(CONFIG) RP = get_persistent_redis(CONFIG) # Disabled due to incompatibility with RPI # if CONFIG_LOCATION_POLLER_INTERVAL > 0: # log("Initializing GPS Location Poller ...") # GPS_LOC = GpsLocationPoller(GPS_POLLER, R, CONFIG_LOCATION_POLLER_INTERVAL) # GPS_LOC.start() # else: # log("GPS Location Poller is disabled. To enable, set [DataPoller].location_polling in config file > 0")
def stop(self, timeout=5): log("Stopping {} ...".format(self.__class__.__name__)) self._running = False self.join(timeout) if self.isAlive(): raise ThreadStopTimeoutError
def load_image(self, image_path): if image_path not in self.image_store: self.image_store[image_path] = load_image(image_path) else: log("Image \"{}\" already loaded".format(image_path))
def run(self): log("{} has started".format(self.__class__.__name__)) while self._running: self._do() if self._interval: sleep(self._interval)
# print(data) return data if __name__ == "__main__": EXIT_CODE = EXIT_CODES['OK'] CONFIG = init_config_env('CARPI_NETD_CONF', ['net-daemon.conf', '/etc/carpi/net-daemon.conf']) boot_print(APP_NAME) CONFIG_DATAPOLLER_INTERVAL = CONFIG.getfloat('DataPoller', 'interval') / 1000 CONFIG_IFACE_ALIAS_ETH0 = CONFIG.get('Interface_Alias', 'eth0') CONFIG_IFACE_ALIAS_WLAN0 = CONFIG.get('Interface_Alias', 'wlan0') CONFIG_IFACE_ALIAS_WLAN1 = CONFIG.get('Interface_Alias', 'wlan1') log("Starting Data Poller ...") POLLER = NetDataPoller(CONFIG_DATAPOLLER_INTERVAL) POLLER.start() log("Initialize Redis Connection ...") R = get_redis(CONFIG) try: log("Network Info Daemon is running ...") while True: ips = POLLER.get_current_data() if ips: r_data = prepare_dict(NetworkInfoRedisKeys.KEYS) if CONFIG_IFACE_ALIAS_ETH0: ip = get_iface_address(ips, CONFIG_IFACE_ALIAS_ETH0)
def __init__(self, rect, redis, pers_redis, title='CarPi', fullscreen=False): log("Initializing CarPiUIApp ...") pqApp.__init__(self, rect=rect, title=title, fullscreen=fullscreen) # Internal Data Storage & Processing self.image_store = {} self._pages = {} self._redis_pages = {} self._predis_pages = {} self._current_page = None # type: str self._fetcher = None # type: RedisBackgroundFetcher self._predis_fetcher = None # type: RedisBackgroundFetcher self._redis = redis # type: Redis self._pers_redis = pers_redis # type: Redis # Tabs self._gps_tab_button = None # type: Button self._music_tab_button = None # type: Button self._settings_tab_button = None # type: Button # Status Icons self._gps_status_icon = None # type: Image self._obd_status_icon = None # type: Image # GPS Data self._speed_label = None # type: Text self._speed_unit = None # type: Text self._speed_graph = None # type: Graph self._location_label = None # type: Text self._gps_status_icon = None # type: Image self._car_status_icon = None # type: Image # Trip Data self._trip_meter = None # type: Text self._odo_meter = None # type: Text self._trip_odo_unit = None # type: Text # Status Bar self._ethernet_status_icon = None # type: Image self._wlan0_status_icon = None # type: Image self._time_label = None # type: Text # Music Display self._current_title = None # type: Text self._current_artist = None # type: Text self._current_album = None # type: Text # Music Status self._current_song_time = None # type: Text self._current_song_time_bar = None # type: ProgressBar # Music Controls self._next_song_button = None # type: Button self._prev_song_button = None # type: Button self._play_song_button = None # type: Button # Load Resources self._load() # Init Controls self._init_controls() # Define UI Pages gps_page = [ self._speed_label, self._speed_graph, self._speed_unit, self._odo_meter, self._trip_meter, self._trip_odo_unit, self._location_label ] music_page = [ self._current_title, self._current_artist, self._current_album, self._current_song_time, self._current_song_time_bar, self._next_song_button, self._prev_song_button, self._play_song_button ] settings_page = [] self._pages[CarPiUIApp.PAGE_GPS] = gps_page self._pages[CarPiUIApp.PAGE_MUSIC] = music_page self._pages[CarPiUIApp.PAGE_SETTINGS] = settings_page # Define Redis Pages gps_r_page = [ # Alive Keys GpsRedisKeys.KEY_ALIVE, NetworkInfoRedisKeys.KEY_ALIVE, MpdDataRedisKeys.KEY_ALIVE, # Always present keys NetworkInfoRedisKeys.KEY_ETH0_IP, NetworkInfoRedisKeys.KEY_WLAN0_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN0_SSID, NetworkInfoRedisKeys.KEY_WLAN1_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN1_SSID, GpsRedisKeys.KEY_SPEED, GpsRedisKeys.KEY_SPEED_KMH, MpdDataRedisKeys.KEY_STATE, # OBD & Fuel Consumption ObdRedisKeys.KEY_ALIVE, ObdRedisKeys.KEY_ENGINE_RPM, ObdRedisKeys.KEY_INTAKE_TEMP, ObdRedisKeys.KEY_INTAKE_MAP, ObdRedisKeys.KEY_VEHICLE_SPEED, # Specific Keys GpsRedisKeys.KEY_EPX, GpsRedisKeys.KEY_EPY ] music_r_page = [ # Alive Keys GpsRedisKeys.KEY_ALIVE, NetworkInfoRedisKeys.KEY_ALIVE, MpdDataRedisKeys.KEY_ALIVE, # Always present keys NetworkInfoRedisKeys.KEY_ETH0_IP, NetworkInfoRedisKeys.KEY_WLAN0_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN0_SSID, NetworkInfoRedisKeys.KEY_WLAN1_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN1_SSID, GpsRedisKeys.KEY_SPEED, GpsRedisKeys.KEY_SPEED_KMH, MpdDataRedisKeys.KEY_STATE, # OBD & Fuel Consumption ObdRedisKeys.KEY_ALIVE, ObdRedisKeys.KEY_ENGINE_RPM, ObdRedisKeys.KEY_INTAKE_TEMP, ObdRedisKeys.KEY_INTAKE_MAP, ObdRedisKeys.KEY_VEHICLE_SPEED, # Specific Keys MpdDataRedisKeys.KEY_SONG_TITLE, MpdDataRedisKeys.KEY_SONG_ARTIST, MpdDataRedisKeys.KEY_SONG_ALBUM, MpdDataRedisKeys.KEY_CURRENT_TIME, MpdDataRedisKeys.KEY_CURRENT_TIME_FORMATTED ] settings_r_page = [ # Alive Keys GpsRedisKeys.KEY_ALIVE, NetworkInfoRedisKeys.KEY_ALIVE, MpdDataRedisKeys.KEY_ALIVE, # Always present keys NetworkInfoRedisKeys.KEY_ETH0_IP, NetworkInfoRedisKeys.KEY_WLAN0_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN0_SSID, NetworkInfoRedisKeys.KEY_WLAN1_STRENGTH, NetworkInfoRedisKeys.KEY_WLAN1_SSID, GpsRedisKeys.KEY_SPEED_KMH, MpdDataRedisKeys.KEY_STATE, # OBD & Fuel Consumption ObdRedisKeys.KEY_ALIVE, ObdRedisKeys.KEY_ENGINE_RPM, ObdRedisKeys.KEY_INTAKE_TEMP, ObdRedisKeys.KEY_INTAKE_MAP, ObdRedisKeys.KEY_VEHICLE_SPEED, # Specific Keys ] self._redis_pages[CarPiUIApp.PAGE_GPS] = gps_r_page self._redis_pages[CarPiUIApp.PAGE_MUSIC] = music_r_page self._redis_pages[CarPiUIApp.PAGE_SETTINGS] = settings_r_page # Define Persistent Redis Pages self._predis_pages[CarPiUIApp.PAGE_GPS] = PersistentGpsRedisKeys.KEYS self._predis_pages[CarPiUIApp.PAGE_MUSIC] = [] self._predis_pages[CarPiUIApp.PAGE_SETTINGS] = []
""" from pqGUI import * from PygameUtils import load_image, init_pygame from CarPiLogging import log, boot_print, end_print, print_unhandled_exception, EXIT_CODES from CarPiConfig import init_config_env from RedisUtils import get_redis, RedisBackgroundFetcher from RedisKeys import GpsRedisKeys, NetworkInfoRedisKeys from math import isnan from redis import exceptions as redis_exceptions from datetime import datetime import os import sys import time log("FBDEV: " + os.environ.get("SDL_FBDEV", '<nodev>')) log("MOUSE: [" + os.environ.get("SDL_MOUSEDRV", '<nodrv>') + "] " + os.environ.get("SDL_MOUSEDEV", '<nodev>')) APP_NAME = os.path.basename(__file__) EXIT_CODE = EXIT_CODES['OK'] FONT_DEFAULT = os.path.join('res', 'fonts', 'Vera.ttf') FONT_7SEGM = os.path.join('res', 'fonts', 'DigitalCounter7.ttf') FONT_DOTMTX = os.path.join('res', 'fonts', 'scoreboard.ttf') IMAGE_GPSSAT_OFF = os.path.join('res', 'img', 'gpssat-off.png') IMAGE_GPSSAT_OK = os.path.join('res', 'img', 'gpssat-ok.png') IMAGE_GPSSAT_WARN = os.path.join('res', 'img', 'gpssat-warn.png') IMAGE_GPSSAT_ERROR = os.path.join('res', 'img', 'gpssat-error.png') IMAGE_CAR_OFF = os.path.join('res', 'img', 'car-off.png')