Example #1
0
def test_clobber(config):

    config01 = {
        'foo': 'bar'
    }
    config02 = {
        'bar': 'foo'
    }

    assert config01 != config02

    save_config('foo', config01)
    config03 = load_config('foo')

    assert config01 == config03

    save_config('foo', config02)
    config04 = load_config('foo')

    assert config02 == config04
    assert config01 != config04

    conf_fn = '{}/conf_files/foo.yaml'.format(os.getenv('POCS'))
    os.remove(conf_fn)
    assert os.path.exists(conf_fn) is False
Example #2
0
def test_multiple_config():
    config01 = {'foo': 1}
    config02 = {'foo': 2, 'bar': 42}
    config03 = {'bam': 'boo'}

    assert config01 != config02

    f01 = str(uuid.uuid4())
    f02 = str(uuid.uuid4())
    f03 = str(uuid.uuid4())

    save_config(f01, config01)
    save_config(f02, config02)
    save_config(f03, config03)

    config04 = load_config(f01)
    config05 = load_config(f02)
    config06 = load_config(f03)

    assert config01 == config04
    assert config02 == config05
    assert config03 == config06

    config07 = load_config([f01, f02], ignore_local=True)
    config08 = load_config([f02, f01], ignore_local=True)

    assert config07 != config01
    assert config07 == config02

    assert config08 != config01
    assert config08 != config02
    assert config08 != config05

    assert 'foo' not in config06
    assert 'bar' not in config06
    assert 'foo' in config05
    assert 'foo' in config07
    assert 'foo' in config08
    assert 'bar' in config05
    assert 'bar' in config07
    assert 'bar' in config08
    assert 'bam' in config06

    assert config07['foo'] == 2
    assert config08['foo'] == 1

    os.remove('{}/conf_files/{}.yaml'.format(os.getenv('POCS'), f01))
    os.remove('{}/conf_files/{}.yaml'.format(os.getenv('POCS'), f02))
    os.remove('{}/conf_files/{}.yaml'.format(os.getenv('POCS'), f03))
Example #3
0
def _make_pretty_from_fits(fname, timeout=15, **kwargs):
    config = load_config()

    title = '{} {}'.format(kwargs.get('title', ''), current_time().isot)

    new_filename = fname.replace('.fits', '.jpg')

    data = fits.getdata(fname)
    plt.imshow(data, cmap='cubehelix_r', origin='lower')
    plt.title(title)
    plt.savefig(new_filename)

    image_dir = config['directories']['images']

    ln_fn = '{}/latest.jpg'.format(image_dir)

    try:
        os.remove(ln_fn)
    except FileNotFoundError:
        pass

    try:
        os.symlink(new_filename, ln_fn)
    except Exception as e:
        warn("Can't link latest image: {}".format(e))

    return new_filename
Example #4
0
    def __init__(self, *args, **kwargs):
        # Load the default and local config files
        global _config
        if _config is None:
            ignore_local_config = kwargs.get('ignore_local_config', False)
            _config = config.load_config(ignore_local=ignore_local_config)

        self.__version__ = __version__

        # Update with run-time config
        if 'config' in kwargs:
            _config.update(kwargs['config'])

        self._check_config(_config)
        self.config = _config

        self.logger = kwargs.get('logger')
        if not self.logger:
            self.logger = get_root_logger()

        self.config['simulator'] = hardware.get_simulator_names(config=self.config, kwargs=kwargs)

        # Set up connection to database
        db = kwargs.get('db', self.config['db']['name'])
        _db = PanMongo(db=db)

        self.db = _db
Example #5
0
def camera(request, images_dir):
    if request.param[0] == SimCamera:
        camera = request.param[0](focuser={'model': 'simulator',
                                           'focus_port': '/dev/ttyFAKE',
                                           'initial_position': 20000,
                                           'autofocus_range': (40, 80),
                                           'autofocus_step': (10, 20),
                                           'autofocus_seconds': 0.1,
                                           'autofocus_size': 500,
                                           'autofocus_keep_files': False})
    else:
        # Load the local config file and look for camera configurations of the specified type
        configs = []
        local_config = load_config('pocs_local', ignore_local=True)
        camera_info = local_config.get('cameras')
        if camera_info:
            # Local config file has a cameras section
            camera_configs = camera_info.get('devices')
            if camera_configs:
                # Local config file camera section has a devices list
                for camera_config in camera_configs:
                    if camera_config['model'] == request.param[1]:
                        # Camera config is the right type
                        configs.append(camera_config)

        if not configs:
            pytest.skip(
                "Found no {} configs in pocs_local.yaml, skipping tests".format(request.param[1]))

        # Create and return an camera based on the first config
        camera = request.param[0](**configs[0])

    camera.config['directories']['images'] = images_dir
    return camera
Example #6
0
    def __init__(self, auto_detect=False, *args, **kwargs):
        self.config = load_config(config_files='peas')
        self.logger = get_root_logger()

        assert 'environment' in self.config
        assert type(self.config['environment']) is dict, \
            self.logger.warning("Environment config variable not set correctly. No sensors listed")

        self.db = None
        self.messaging = None

        # Store each serial reader
        self.serial_readers = dict()

        if auto_detect:
            for port_num in range(9):
                port = '/dev/ttyACM{}'.format(port_num)
                if os.path.exists(port):
                    self.logger.debug("Trying to connect on {}".format(port))

                    sensor_name = None
                    serial_reader = self._connect_serial(port)

                    num_tries = 5
                    self.logger.debug("Getting name on {}".format(port))
                    while num_tries > 0:
                        try:
                            data = serial_reader.get_reading()
                        except yaml.parser.ParserError:
                            pass
                        except AttributeError:
                            pass
                        else:
                            try:
                                if 'name' in data:
                                    sensor_name = data['name']
                                    num_tries = 0
                            except Exception as e:
                                self.logger.warning("Read on serial: {}".format(e))
                        num_tries -= 1

                    if sensor_name is not None:
                        self.serial_readers[sensor_name] = {
                            'reader': serial_reader,
                        }
        else:
            # Try to connect to a range of ports
            for sensor_name in self.config['environment'].keys():
                try:
                    port = self.config['environment'][sensor_name]['serial_port']
                except TypeError:
                    continue
                except KeyError:
                    continue

                serial_reader = self._connect_serial(port)
                self.serial_readers[sensor_name] = {
                    'reader': serial_reader,
                    'port': port,
                }
Example #7
0
def pocs(target):
    try:
        del os.environ['POCSTIME']
    except KeyError:
        pass

    config = load_config(ignore_local=False)

    pocs = POCS(simulator=['weather', 'night', 'camera'],
                run_once=True,
                config=config,
                db='panoptes_testing',
                messaging=True)

    pocs.observatory.scheduler.fields_list = [
        {
            'name': 'Testing Target',
            'position': target.to_string(style='hmsdms'),
            'priority': '100',
            'exp_time': 2,
            'min_nexp': 2,
            'exp_set_size': 2,
        },
    ]

    yield pocs

    pocs.power_down()
Example #8
0
def focuser(request):
    if request.param[0] == SimFocuser:
        # Simulated focuser, just create one and return it
        return request.param[0]()
    else:
        # Load the local config file and look for focuser configurations of the specified type
        focuser_configs = []
        local_config = load_config('pocs_local', ignore_local=True)
        camera_info = local_config.get('cameras')
        if camera_info:
            # Local config file has a cameras section
            camera_configs = camera_info.get('devices')
            if camera_configs:
                # Local config file camera section has a devices list
                for camera_config in camera_configs:
                    focuser_config = camera_config.get('focuser', None)
                    if focuser_config and focuser_config[
                            'model'] == request.param[1]:
                        # Camera config has a focuser section, and it's the right type
                        focuser_configs.append(focuser_config)

        if not focuser_configs:
            pytest.skip(
                "Found no {} configurations in pocs_local.yaml, skipping tests"
                .format(request.param[1]))

        # Create and return a Focuser based on the first config
        return request.param[0](**focuser_configs[0])
Example #9
0
    def __init__(self, *args, **kwargs):
        # Load the default and local config files
        global _config
        if _config is None:
            ignore_local_config = kwargs.get('ignore_local_config', False)
            _config = config.load_config(ignore_local=ignore_local_config)

        self.__version__ = __version__

        # Update with run-time config
        if 'config' in kwargs:
            _config.update(kwargs['config'])

        self._check_config(_config)
        self.config = _config

        self.logger = kwargs.get('logger')
        if not self.logger:
            self.logger = get_root_logger()

        self.config['simulator'] = hardware.get_simulator_names(
            config=self.config, kwargs=kwargs)

        # Set up connection to database
        db = kwargs.get('db', self.config['db']['name'])
        _db = PanMongo(db=db)

        self.db = _db
Example #10
0
def config():
    pocs.base.reset_global_config()

    global _one_time_config
    if not _one_time_config:
        _one_time_config = load_config(ignore_local=True, simulator=['all'])
        _one_time_config['db']['name'] = 'panoptes_testing'

    return copy.deepcopy(_one_time_config)
Example #11
0
def config():
    pocs.base.reset_global_config()

    global _one_time_config
    if not _one_time_config:
        _one_time_config = load_config(ignore_local=True, simulator=['all'])
        _one_time_config['db']['name'] = 'panoptes_testing'

    return copy.deepcopy(_one_time_config)
Example #12
0
def test_full_path():
    temp_config_path = '/tmp/{}.yaml'.format(uuid.uuid4())
    temp_config = {'foo': 42}
    save_config(temp_config_path, temp_config)

    c = load_config(temp_config_path)

    assert c == temp_config
    os.remove(temp_config_path)
Example #13
0
def test_local_config():

    _local_config_file = '{}/conf_files/pocs_local.yaml'.format(os.getenv('POCS'))

    if not os.path.exists(_local_config_file):
        conf = load_config(ignore_local=True)
        assert conf['name'] == 'Generic PANOPTES Unit'

        local_yaml = {
            'name': 'ConfTestName'
        }
        with open(_local_config_file, 'w') as f:
            f.write(yaml.dump(local_yaml))
        conf = load_config()
        assert conf['name'] != 'Generic PANOPTES Unit'
        os.remove(_local_config_file)
    else:
        conf = load_config()
        assert conf['name'] != 'Generic PANOPTES Unit'
Example #14
0
def test_no_config():
    # Move existing config to temp
    _config_file = '{}/conf_files/pocs.yaml'.format(os.getenv('POCS'))
    _config_file_temp = '{}/conf_files/pocs_temp.yaml'.format(os.getenv('POCS'))
    os.rename(_config_file, _config_file_temp)

    config = load_config(ignore_local=True)

    assert len(config.keys()) == 0

    os.rename(_config_file_temp, _config_file)
Example #15
0
    def setup(self):

        self.config = load_config(ignore_local=True)

        location = self.config['location']

        with pytest.raises(AssertionError):
            mount = Mount(location)

        loc = EarthLocation(lon=location['longitude'],
                            lat=location['latitude'],
                            height=location['elevation'])

        mount = Mount(loc)
        assert mount is not None
Example #16
0
    def setup(self):

        self.config = load_config(ignore_local=True)

        location = self.config['location']

        with pytest.raises(AssertionError):
            mount = Mount(location)

        loc = EarthLocation(
            lon=location['longitude'],
            lat=location['latitude'],
            height=location['elevation'])

        mount = Mount(loc)
        assert mount is not None
Example #17
0
    def __init__(self, date_string=None, data_file=None, *args, **kwargs):
        super(WeatherPlotter, self).__init__()
        self.args = args
        self.kwargs = kwargs

        config = load_config(config_files=['peas'])
        self.cfg = config['weather']['plot']
        location_cfg = config.get('location', None)

        self.thresholds = config['weather'].get('aag_cloud', None)

        if not date_string:
            self.today = True
            self.date = dt.utcnow()
            self.date_string = self.date.strftime('%Y%m%dUT')
            self.start = self.date - tdelta(1, 0)
            self.end = self.date
            self.lhstart = self.date - tdelta(0, 60 * 60)
            self.lhend = self.date + tdelta(0, 5 * 60)

        else:
            self.today = False
            self.date = dt.strptime('{} 23:59:59'.format(date_string),
                                    '%Y%m%dUT %H:%M:%S')
            self.date_string = date_string
            self.start = dt(self.date.year, self.date.month, self.date.day, 0, 0, 0, 0)
            self.end = dt(self.date.year, self.date.month, self.date.day, 23, 59, 59, 0)
        print('Creating weather plotter for {}'.format(self.date_string))

        self.twilights = self.get_twilights(location_cfg)

        self.table = self.get_table_data(data_file)

        if self.table is None:
            warnings.warn("No data")
            sys.exit(0)

        self.time = pd.to_datetime(self.table['date'])
        first = self.time[0].isoformat()
        last = self.time[-1].isoformat()
        print('  Retrieved {} entries between {} and {}'.format(
              len(self.table), first, last))

        if self.today:
            self.current_values = self.table[-1]
        else:
            self.current_values = None
Example #18
0
    def __init__(self,
                 webcam_config,
                 frames=255,
                 resolution="1600x1200",
                 brightness="50%",
                 gain="50%"):

        self.config = load_config(config_files='peas')

        self.logger = get_root_logger()

        self._today_dir = None

        self.webcam_dir = self.config['directories'].get('webcam', '/var/panoptes/webcams/')
        assert os.path.exists(self.webcam_dir), self.logger.warning(
            "Webcam directory must exist: {}".format(self.webcam_dir))

        self.logger.info("Creating webcams")

        # Lookup the webcams
        if webcam_config is None:
            err_msg = "No webcams to connect. Please check config.yaml and all appropriate ports"
            self.logger.warning(err_msg)

        self.webcam_config = webcam_config
        self.name = self.webcam_config.get('name', 'GenericWebCam')

        self.port_name = self.webcam_config.get('port').split('/')[-1]

        # Command for taking pics
        self.cmd = shutil.which('fswebcam')

        # Defaults
        self._timestamp = "%Y-%m-%d %H:%M:%S"
        self._thumbnail_resolution = '240x120'

        # Create the string for the params
        self.base_params = "-F {} -r {} --set brightness={} --set gain={} --jpeg 100 --timestamp \"{}\" ".format(
            frames, resolution, brightness, gain, self._timestamp)

        self.logger.info("{} created".format(self.name))
Example #19
0
def pocs(target):
    try:
        del os.environ['POCSTIME']
    except KeyError:
        pass

    config = load_config(ignore_local=False)

    pocs = POCS(simulator=['weather', 'night', 'camera'], run_once=True,
                config=config, db='panoptes_testing', messaging=True)

    pocs.observatory.scheduler.fields_list = [
        {'name': 'Testing Target',
         'position': target.to_string(style='hmsdms'),
         'priority': '100',
         'exp_time': 2,
         'min_nexp': 2,
         'exp_set_size': 2,
         },
    ]

    yield pocs

    pocs.power_down()
Example #20
0
def location():
    config = load_config(ignore_local=False)
    loc = config['location']
    return EarthLocation(lon=loc['longitude'], lat=loc['latitude'], height=loc['elevation'])
Example #21
0
    def __init__(self, serial_address=None, use_mongo=True):
        self.config = load_config(config_files='peas')
        self.logger = get_root_logger()

        # Read configuration
        self.cfg = self.config['weather']['aag_cloud']

        self.safety_delay = self.cfg.get('safety_delay', 15.)

        self.db = None
        if use_mongo:
            self.db = get_mongodb()

        self.messaging = None

        # Initialize Serial Connection
        if serial_address is None:
            serial_address = self.cfg.get('serial_port', '/dev/ttyUSB0')

        self.logger.debug('Using serial address: {}'.format(serial_address))

        if serial_address:
            self.logger.info('Connecting to AAG Cloud Sensor')
            try:
                self.AAG = serial.Serial(serial_address, 9600, timeout=2)
                self.logger.info("  Connected to Cloud Sensor on {}".format(serial_address))
            except OSError as e:
                self.logger.error('Unable to connect to AAG Cloud Sensor')
                self.logger.error('  {}'.format(e.errno))
                self.logger.error('  {}'.format(e.strerror))
                self.AAG = None
            except BaseException:
                self.logger.error("Unable to connect to AAG Cloud Sensor")
                self.AAG = None
        else:
            self.AAG = None

        # Thresholds

        # Initialize Values
        self.last_update = None
        self.safe = None
        self.ambient_temp = None
        self.sky_temp = None
        self.wind_speed = None
        self.internal_voltage = None
        self.LDR_resistance = None
        self.rain_sensor_temp = None
        self.PWM = None
        self.errors = None
        self.switch = None
        self.safe_dict = None
        self.hibernate = 0.500  # time to wait after failed query

        # Set Up Heater
        if 'heater' in self.cfg:
            self.heater_cfg = self.cfg['heater']
        else:
            self.heater_cfg = {
                'low_temp': 0,
                'low_delta': 6,
                'high_temp': 20,
                'high_delta': 4,
                'min_power': 10,
                'impulse_temp': 10,
                'impulse_duration': 60,
                'impulse_cycle': 600,
            }
        self.heater_PID = PID(Kp=3.0, Ki=0.02, Kd=200.0,
                              max_age=300,
                              output_limits=[self.heater_cfg['min_power'], 100])

        self.impulse_heating = None
        self.impulse_start = None

        # Command Translation
        self.commands = {'!A': 'Get internal name',
                         '!B': 'Get firmware version',
                         '!C': 'Get values',
                         '!D': 'Get internal errors',
                         '!E': 'Get rain frequency',
                         '!F': 'Get switch status',
                         '!G': 'Set switch open',
                         '!H': 'Set switch closed',
                         'P\d\d\d\d!': 'Set PWM value',
                         '!Q': 'Get PWM value',
                         '!S': 'Get sky IR temperature',
                         '!T': 'Get sensor temperature',
                         '!z': 'Reset RS232 buffer pointers',
                         '!K': 'Get serial number',
                         'v!': 'Query if anemometer enabled',
                         'V!': 'Get wind speed',
                         'M!': 'Get electrical constants',
                         '!Pxxxx': 'Set PWM value to xxxx',
                         }
        self.expects = {'!A': '!N\s+(\w+)!',
                        '!B': '!V\s+([\d\.\-]+)!',
                        '!C': '!6\s+([\d\.\-]+)!4\s+([\d\.\-]+)!5\s+([\d\.\-]+)!',
                        '!D': '!E1\s+([\d\.]+)!E2\s+([\d\.]+)!E3\s+([\d\.]+)!E4\s+([\d\.]+)!',
                        '!E': '!R\s+([\d\.\-]+)!',
                        '!F': '!Y\s+([\d\.\-]+)!',
                        'P\d\d\d\d!': '!Q\s+([\d\.\-]+)!',
                        '!Q': '!Q\s+([\d\.\-]+)!',
                        '!S': '!1\s+([\d\.\-]+)!',
                        '!T': '!2\s+([\d\.\-]+)!',
                        '!K': '!K(\d+)\s*\\x00!',
                        'v!': '!v\s+([\d\.\-]+)!',
                        'V!': '!w\s+([\d\.\-]+)!',
                        'M!': '!M(.{12})',
                        }
        self.delays = {
            '!E': 0.350,
            'P\d\d\d\d!': 0.750,
        }

        self.weather_entries = list()

        if self.AAG:
            # Query Device Name
            result = self.query('!A')
            if result:
                self.name = result[0].strip()
                self.logger.info('  Device Name is "{}"'.format(self.name))
            else:
                self.name = ''
                self.logger.warning('  Failed to get Device Name')
                sys.exit(1)

            # Query Firmware Version
            result = self.query('!B')
            if result:
                self.firmware_version = result[0].strip()
                self.logger.info('  Firmware Version = {}'.format(self.firmware_version))
            else:
                self.firmware_version = ''
                self.logger.warning('  Failed to get Firmware Version')
                sys.exit(1)

            # Query Serial Number
            result = self.query('!K')
            if result:
                self.serial_number = result[0].strip()
                self.logger.info('  Serial Number: {}'.format(self.serial_number))
            else:
                self.serial_number = ''
                self.logger.warning('  Failed to get Serial Number')
                sys.exit(1)
Example #22
0
def test_no_parse():
    config = load_config(parse=False, ignore_local=True)
    lat = config['location']['latitude']
    assert isinstance(lat, u.Quantity) is False
    assert isinstance(lat, float)
Example #23
0
def get_root_logger(profile='panoptes', log_config=None):
    """Creates a root logger for PANOPTES used by the PanBase object.

    Args:
        profile (str, optional): The name of the logger to use, defaults
            to 'panoptes'.
        log_config (dict|None, optional): Configuration options for the logger.
            See https://docs.python.org/3/library/logging.config.html for
            available options. Default is `None`, which then looks up the
            values in the `log.yaml` config file.

    Returns:
        logger(logging.logger): A configured instance of the logger
    """

    # Get log info from config
    log_config = log_config if log_config else load_config('log').get('logger', {})

    # If we already created a logger for this profile and log_config, return that.
    logger_key = (profile, json.dumps(log_config, sort_keys=True))
    try:
        return all_loggers[logger_key]
    except KeyError:
        pass

    # Alter the log_config to use UTC times
    if log_config.get('use_utc', True):
        for name, formatter in log_config['formatters'].items():
            log_config['formatters'][name].setdefault('()', _UTCFormatter)
        log_fname_datetime = datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')
    else:
        log_fname_datetime = datetime.datetime.now().strftime('%Y%m%dT%H%M%SZ')

    # Setup log file names
    invoked_script = os.path.basename(sys.argv[0])
    log_dir = '{}/logs'.format(os.getenv('PANDIR', gettempdir()))
    log_fname = '{}-{}-{}'.format(invoked_script, os.getpid(), log_fname_datetime)
    log_symlink = '{}/{}.log'.format(log_dir, invoked_script)

    # Set log filename and rotation
    for handler in log_config.get('handlers', []):
        # Set the filename
        full_log_fname = '{}/{}-{}.log'.format(log_dir, log_fname, handler)
        log_config['handlers'][handler].setdefault('filename', full_log_fname)

        # Setup the TimedRotatingFileHandler for middle of day
        log_config['handlers'][handler].setdefault('atTime', datetime.time(hour=11, minute=30))

        if handler == 'all':
            # Create a symlink to the log file with just the name of the script,
            # not the date and pid, as this makes it easier to find the latest file.
            try:
                os.unlink(log_symlink)
            except FileNotFoundError:  # pragma: no cover
                pass
            finally:
                os.symlink(full_log_fname, log_symlink)

    # Configure the logger
    logging.config.dictConfig(log_config)

    # Get the logger and set as attribute to class
    logger = logging.getLogger(profile)

    # Don't want log messages from state machine library, it is very noisy and
    # we have our own way of logging state transitions
    logging.getLogger('transitions.core').setLevel(logging.WARNING)

    # Set custom LogRecord
    logging.setLogRecordFactory(StrFormatLogRecord)

    # Add a filter for better filename/lineno
    logger.addFilter(FilenameLineFilter())

    logger.info('{:*^80}'.format(' Starting PanLogger '))
    all_loggers[logger_key] = logger
    return logger
        default=None,
        help=
        "Connect to a specific database, otherwise connect to all in config.")
    parser.add_argument('--key-file',
                        default=None,
                        help="JSON service account key location.")
    parser.add_argument('--proxy-cmd',
                        default=None,
                        help="The Google Cloud SQL proxy script")
    parser.add_argument('--verbose',
                        action='store_true',
                        default=False,
                        help="Print results to stdout, default False.")
    args = parser.parse_args()

    config = load_config(args.config)
    try:
        network_config = config['panoptes_network']
        if args.verbose:
            print("Found config:")
            pprint(network_config)
    except KeyError as e:
        print(
            "Invalid configuration. Check panoptes_network config. {}".format(
                e))
        sys.exit(1)

    # Try to lookup service account key from config if none provided
    key_file = args.key_file
    if not key_file:
        try:
Example #25
0
    def __init__(self, serial_address=None, use_mongo=True):
        self.config = load_config(config_files='peas')
        self.logger = get_root_logger()

        # Read configuration
        self.cfg = self.config['weather']['aag_cloud']

        self.safety_delay = self.cfg.get('safety_delay', 15.)

        self.db = None
        if use_mongo:
            self.db = get_mongodb()

        self.messaging = None

        # Initialize Serial Connection
        if serial_address is None:
            serial_address = self.cfg.get('serial_port', '/dev/ttyUSB0')

        self.logger.debug('Using serial address: {}'.format(serial_address))

        if serial_address:
            self.logger.info('Connecting to AAG Cloud Sensor')
            try:
                self.AAG = serial.Serial(serial_address, 9600, timeout=2)
                self.logger.info(
                    "  Connected to Cloud Sensor on {}".format(serial_address))
            except OSError as e:
                self.logger.error('Unable to connect to AAG Cloud Sensor')
                self.logger.error('  {}'.format(e.errno))
                self.logger.error('  {}'.format(e.strerror))
                self.AAG = None
            except BaseException:
                self.logger.error("Unable to connect to AAG Cloud Sensor")
                self.AAG = None
        else:
            self.AAG = None

        # Thresholds

        # Initialize Values
        self.last_update = None
        self.safe = None
        self.ambient_temp = None
        self.sky_temp = None
        self.wind_speed = None
        self.internal_voltage = None
        self.LDR_resistance = None
        self.rain_sensor_temp = None
        self.PWM = None
        self.errors = None
        self.switch = None
        self.safe_dict = None
        self.hibernate = 0.500  # time to wait after failed query

        # Set Up Heater
        if 'heater' in self.cfg:
            self.heater_cfg = self.cfg['heater']
        else:
            self.heater_cfg = {
                'low_temp': 0,
                'low_delta': 6,
                'high_temp': 20,
                'high_delta': 4,
                'min_power': 10,
                'impulse_temp': 10,
                'impulse_duration': 60,
                'impulse_cycle': 600,
            }
        self.heater_PID = PID(
            Kp=3.0,
            Ki=0.02,
            Kd=200.0,
            max_age=300,
            output_limits=[self.heater_cfg['min_power'], 100])

        self.impulse_heating = None
        self.impulse_start = None

        # Command Translation
        self.commands = {
            '!A': 'Get internal name',
            '!B': 'Get firmware version',
            '!C': 'Get values',
            '!D': 'Get internal errors',
            '!E': 'Get rain frequency',
            '!F': 'Get switch status',
            '!G': 'Set switch open',
            '!H': 'Set switch closed',
            'P\d\d\d\d!': 'Set PWM value',
            '!Q': 'Get PWM value',
            '!S': 'Get sky IR temperature',
            '!T': 'Get sensor temperature',
            '!z': 'Reset RS232 buffer pointers',
            '!K': 'Get serial number',
            'v!': 'Query if anemometer enabled',
            'V!': 'Get wind speed',
            'M!': 'Get electrical constants',
            '!Pxxxx': 'Set PWM value to xxxx',
        }
        self.expects = {
            '!A': '!N\s+(\w+)!',
            '!B': '!V\s+([\d\.\-]+)!',
            '!C': '!6\s+([\d\.\-]+)!4\s+([\d\.\-]+)!5\s+([\d\.\-]+)!',
            '!D':
            '!E1\s+([\d\.]+)!E2\s+([\d\.]+)!E3\s+([\d\.]+)!E4\s+([\d\.]+)!',
            '!E': '!R\s+([\d\.\-]+)!',
            '!F': '!Y\s+([\d\.\-]+)!',
            'P\d\d\d\d!': '!Q\s+([\d\.\-]+)!',
            '!Q': '!Q\s+([\d\.\-]+)!',
            '!S': '!1\s+([\d\.\-]+)!',
            '!T': '!2\s+([\d\.\-]+)!',
            '!K': '!K(\d+)\s*\\x00!',
            'v!': '!v\s+([\d\.\-]+)!',
            'V!': '!w\s+([\d\.\-]+)!',
            'M!': '!M(.{12})',
        }
        self.delays = {
            '!E': 0.350,
            'P\d\d\d\d!': 0.750,
        }

        self.weather_entries = list()

        if self.AAG:
            # Query Device Name
            result = self.query('!A')
            if result:
                self.name = result[0].strip()
                self.logger.info('  Device Name is "{}"'.format(self.name))
            else:
                self.name = ''
                self.logger.warning('  Failed to get Device Name')
                sys.exit(1)

            # Query Firmware Version
            result = self.query('!B')
            if result:
                self.firmware_version = result[0].strip()
                self.logger.info('  Firmware Version = {}'.format(
                    self.firmware_version))
            else:
                self.firmware_version = ''
                self.logger.warning('  Failed to get Firmware Version')
                sys.exit(1)

            # Query Serial Number
            result = self.query('!K')
            if result:
                self.serial_number = result[0].strip()
                self.logger.info('  Serial Number: {}'.format(
                    self.serial_number))
            else:
                self.serial_number = ''
                self.logger.warning('  Failed to get Serial Number')
                sys.exit(1)
Example #26
0
def config():
    config = load_config(ignore_local=True, simulator=['all'])
    config['db']['name'] = 'panoptes_testing'
    return config
Example #27
0
def get_root_logger(profile='panoptes', log_config=None):
    """Creates a root logger for PANOPTES used by the PanBase object.

    Args:
        profile (str, optional): The name of the logger to use, defaults
            to 'panoptes'.
        log_config (dict|None, optional): Configuration options for the logger.
            See https://docs.python.org/3/library/logging.config.html for
            available options. Default is `None`, which then looks up the
            values in the `log.yaml` config file.

    Returns:
        logger(logging.logger): A configured instance of the logger
    """

    # Get log info from config
    log_config = log_config if log_config else load_config('log').get(
        'logger', {})

    # If we already created a logger for this profile and log_config, return that.
    logger_key = (profile, json.dumps(log_config, sort_keys=True))
    try:
        return all_loggers[logger_key]
    except KeyError:
        pass

    # Alter the log_config to use UTC times
    if log_config.get('use_utc', True):
        for name, formatter in log_config['formatters'].items():
            log_config['formatters'][name].setdefault('()', _UTCFormatter)
        log_fname_datetime = datetime.datetime.utcnow().strftime(
            '%Y%m%dT%H%M%SZ')
    else:
        log_fname_datetime = datetime.datetime.now().strftime('%Y%m%dT%H%M%SZ')

    # Setup log file names
    invoked_script = os.path.basename(sys.argv[0])
    log_dir = '{}/logs'.format(os.getenv('PANDIR', gettempdir()))
    log_fname = '{}-{}-{}'.format(invoked_script, os.getpid(),
                                  log_fname_datetime)
    log_symlink = '{}/{}.log'.format(log_dir, invoked_script)

    # Set log filename and rotation
    for handler in log_config.get('handlers', []):
        # Set the filename
        full_log_fname = '{}/{}-{}.log'.format(log_dir, log_fname, handler)
        log_config['handlers'][handler].setdefault('filename', full_log_fname)

        # Setup the TimedRotatingFileHandler for middle of day
        log_config['handlers'][handler].setdefault(
            'atTime', datetime.time(hour=11, minute=30))

        if handler == 'all':
            # Create a symlink to the log file with just the name of the script,
            # not the date and pid, as this makes it easier to find the latest file.
            try:
                os.unlink(log_symlink)
            except FileNotFoundError:  # pragma: no cover
                pass
            finally:
                os.symlink(full_log_fname, log_symlink)

    # Configure the logger
    logging.config.dictConfig(log_config)

    # Get the logger and set as attribute to class
    logger = logging.getLogger(profile)

    # Don't want log messages from state machine library, it is very noisy and
    # we have our own way of logging state transitions
    logging.getLogger('transitions.core').setLevel(logging.WARNING)

    # Set custom LogRecord
    logging.setLogRecordFactory(StrFormatLogRecord)

    # Add a filter for better filename/lineno
    logger.addFilter(FilenameLineFilter())

    logger.info('{:*^80}'.format(' Starting PanLogger '))
    all_loggers[logger_key] = logger
    return logger
Example #28
0
def location():
    config = load_config(ignore_local=False)
    loc = config['location']
    return EarthLocation(lon=loc['longitude'],
                         lat=loc['latitude'],
                         height=loc['elevation'])