예제 #1
0
class Directories(PathContainer):
    logging: Path = ConfigEntry(Path('log'), description='Folder where the logs will be written to')
    rules: Path = ConfigEntry(Path('rules'), description='Folder from which the rule files will be loaded')
    param: Path = ConfigEntry(Path('param'), description='Folder from which the parameter files will be loaded')
    config: Path = ConfigEntry(Path('config'), description='Folder from which configuration files will be loaded')
    lib: Path = ConfigEntry(Path('lib'), description='Folder where additional libraries can be placed')

    def on_all_values_set(self):
        try:
            # create folder structure if it does not exist
            if not self.rules.is_dir():
                self.rules.mkdir()
            if not self.logging.is_dir():
                self.logging.mkdir()
            if not self.config.is_dir():
                log.info(f'Manual thing configuration disabled! Folder {self.config} does not exist!')

            # add path for libraries
            if self.lib.is_dir():
                lib_path = str(self.lib)
                if lib_path not in sys.path:
                    sys.path.insert(0, lib_path)
                    log.debug(f'Added library folder "{lib_path}" to system path')
        except Exception as e:
            log.error(e)
            print(e)
예제 #2
0
class Logging(ConfigContainer):
    level: str = ConfigEntry(default='INFO',
                             description='Verbosity level for the logfile',
                             validator=log_lvl_validator)
    file: Path = ConfigEntry(
        default_factory=lambda: str(CONFIG._path.with_name('sml2mqtt.log')),
        description='Path to logfile')
예제 #3
0
class General(ConfigContainer):
    listen_only: bool = ConfigEntry(
        False, description='If True HABApp will not change anything on the openHAB instance.'
    )
    wait_for_openhab: bool = ConfigEntry(
        True,
        description='If True HABApp will wait for items from the openHAB instance before loading any rules on startup'
    )
예제 #4
0
def test_path_objects():

    c = ConfigEntry(required=True, default=Path('asdf'))
    c.set_type_hint('test', Path)
    validator = c.set_validator({}, DEFAULT_CONFIGURATION)

    # yaml doesnt provide path -> convert to str
    ret = voluptuous.Schema(validator)({'test': '/my/path'})
    assert ret == {'test': Path('/my/path')}
예제 #5
0
def test_default_value_skip():
    CFG_LOWER.create_optional_keys = False

    ret = {}
    ConfigEntry(required=False, default='skip',
                key_name='key_skip').set_default(ret, CFG_LOWER)
    ConfigEntry(required=True, default='set',
                key_name='key_set').set_default(ret, CFG_LOWER)
    assert ret == {'key_set': 'set'}
예제 #6
0
def test_dict_validator():

    c = ConfigEntry(required=True,
                    default_factory=lambda: {'test_key': 'test_val'})
    c.set_type_hint('test', typing.Dict[str, str])
    validator = c.set_validator({}, DEFAULT_CONFIGURATION)

    ret = voluptuous.Schema(validator)({})
    assert ret == {'test': {'test_key': 'test_val'}}
예제 #7
0
class Ping(ConfigContainer):
    enabled: bool = ConfigEntry(
        True,
        description=
        'If enabled the configured item will show how long it takes to send '
        'an update from HABApp and get the updated value back from openhab'
        'in milliseconds')
    item: str = ConfigEntry('HABApp_Ping', description='Name of the item')
    interval: int = ConfigEntry(10, description='Seconds between two pings')
예제 #8
0
def test_list_validator():

    c = ConfigEntry(required=True, default_factory=lambda: ['test'])
    c.set_type_hint('test', typing.List[str])
    validator = c.set_validator({}, DEFAULT_CONFIGURATION)

    assert {'test': [str]} == validator

    ret = voluptuous.Schema(validator)({})
    assert ret == {'test': ['test']}
예제 #9
0
def test_default_value_create():
    CFG_LOWER.create_optional_keys = True

    ret = {}
    ConfigEntry(required=False, default=5,
                key_name='test_int').set_default(ret, CFG_LOWER)
    assert ret == {'test_int': 5}

    ConfigEntry(required=False, default='TestString',
                key_name='test_str').set_default(ret, CFG_LOWER)
    assert ret == {'test_int': 5, 'test_str': 'TestString'}
예제 #10
0
def test_required():
    c = ConfigEntry(required=True, key_name='test')
    c.set_type_hint('test', int)
    validator = c.set_validator({}, CFG_LOWER)
    with pytest.raises(voluptuous.MultipleInvalid):
        voluptuous.Schema(validator)({})
    voluptuous.Schema(validator)({'test': 5})

    c = ConfigEntry(required=False, key_name='test')
    c.set_type_hint('test', str)
    validator = c.set_validator({}, CFG_LOWER)
    voluptuous.Schema(validator)({})
    voluptuous.Schema(validator)({'test': 'my_str'})
예제 #11
0
class Directories(PathContainer):
    logging: Path = ConfigEntry(
        get_log_folder(Path('log')),
        description='Folder where the logs will be written to')
    rules: Path = ConfigEntry(
        Path('rules'),
        description='Folder from which the rule files will be loaded')
    param: Path = ConfigEntry(
        Path('params'),
        description='Folder from which the parameter files will be loaded')
    config: Path = ConfigEntry(
        Path('config'),
        description='Folder from which configuration files '
        '(e.g. for textual thing configuration) will be loaded')
    lib: Path = ConfigEntry(
        Path('lib'),
        description='Folder where additional libraries can be placed')

    def on_all_values_set(self):

        # Configuration folder of HABApp can not be one of the configured folders
        for name, path in {
                attr: getattr(self, attr)
                for attr in ('rules', 'param', 'config')
        }.items():
            if path == self.parent_folder:
                msg = f'Path for {name} can not be the same as the path for the HABApp config! ({path})'
                log.error(msg)
                sys.exit(msg)

        try:
            # create folder structure if it does not exist
            if not self.rules.is_dir():
                self.rules.mkdir()
            if not self.logging.is_dir():
                self.logging.mkdir()
            if not self.config.is_dir():
                log.info(
                    f'Manual thing configuration disabled! Folder {self.config} does not exist!'
                )

            # add path for libraries
            if self.lib.is_dir():
                lib_path = str(self.lib)
                if lib_path not in sys.path:
                    sys.path.insert(0, lib_path)
                    log.debug(
                        f'Added library folder "{lib_path}" to system path')
        except Exception as e:
            log.error(e)
            print(e)
예제 #12
0
class Location(ConfigContainer):
    latitude: float = ConfigEntry(default=0.0,
                                  validator=voluptuous.Any(float, int))
    longitude: float = ConfigEntry(default=0.0,
                                   validator=voluptuous.Any(float, int))
    elevation: float = ConfigEntry(default=0.0,
                                   validator=voluptuous.Any(float, int))

    def __init__(self):
        super().__init__()

    def on_all_values_set(self):
        log.debug(f'Local Timezone: {eascheduler.const.local_tz}')
        eascheduler.set_location(self.latitude, self.longitude, self.elevation)
예제 #13
0
def test_description():
    data = ruamel.yaml.comments.CommentedMap()
    ConfigEntry(required=True, default=5,
                key_name='key_no_comment').set_default(data, CFG_LOWER)
    ConfigEntry(required=True,
                default=5,
                key_name='key_comment',
                description='Description').set_default(data, CFG_LOWER)

    tmp = io.StringIO()
    ruamel.yaml.YAML().dump(data, tmp)
    output = tmp.getvalue()

    assert output == 'key_no_comment: 5\nkey_comment: 5  # Description\n'
예제 #14
0
class General(ConfigContainer):
    max_wait: int = ConfigEntry(
        default=120,
        key_name='max wait',
        validator=Range(min=2),
        description=
        'Time in seconds sml2mqtt waits for a value change until the value gets republished'
    )
예제 #15
0
class Topics(ConfigContainer):
    base_topic: str = ConfigEntry(
        'sml2mqtt',
        key_name='base topic',
        description='Topic that will prefix all topics')
    last_will: str = ConfigEntry('status',
                                 key_name='last will',
                                 description='Last will topic')
    alias: Dict[str, str] = ConfigEntry(
        default_factory=lambda: {'0100010800ff': 'total_energy'},
        validator={str: str},
        description='These aliases are replaced in the mqtt topics')

    def on_all_values_set(self):
        self.alias = {k: v.replace(' ', '_') for k, v in self.alias.items()}

    def get_topic(self, *args) -> str:
        args = [self.alias.get(a, a) for a in args]
        topic = self.base_topic + '/' + '/'.join(args)
        return topic.replace('//', '/')
예제 #16
0
class Connection(ConfigContainer):
    client_id: str = 'HABApp'
    host: str = ''
    port: int = 8883
    user: str = ''
    password: str = ''
    tls: bool = True
    tls_ca_cert: str = ConfigEntry(
        default='',
        description='Path to a CA certificate that will be treated as trusted')
    tls_insecure: bool = False
예제 #17
0
def test_default_validator():
    c = ConfigEntry(required=True, default=5)
    c.set_type_hint('test', int)
    validator = c.set_validator({}, DEFAULT_CONFIGURATION)

    ret = voluptuous.Schema(validator)({})
    assert ret == {'test': 5}

    ret = voluptuous.Schema(validator)({'test': 7})
    assert ret == {'test': 7}

    c = ConfigEntry(required=True, default='asdf')
    c.set_type_hint('test', str)
    validator = c.set_validator({}, DEFAULT_CONFIGURATION)

    ret = voluptuous.Schema(validator)({})
    assert ret == {'test': 'asdf'}

    ret = voluptuous.Schema(validator)({'test': 'ASDF'})
    assert ret == {'test': 'ASDF'}
예제 #18
0
class Location(ConfigContainer):
    latitude: float = ConfigEntry(default=0.0,
                                  validator=voluptuous.Any(float, int))
    longitude: float = ConfigEntry(default=0.0,
                                   validator=voluptuous.Any(float, int))
    elevation: float = ConfigEntry(default=0.0,
                                   validator=voluptuous.Any(float, int))

    def __init__(self):
        super().__init__()
        self.astral: _astral.Location = None

    def on_all_values_set(self):
        tz = tzlocal.get_localzone()
        tz_name = str(tz)
        log.debug(f'Local Timezone: {tz_name}')

        self.astral = _astral.Location()
        self.astral.name = 'HABApp'
        self.astral.latitude = self.latitude
        self.astral.longitude = self.longitude
        self.astral.elevation = self.elevation
        self.astral.timezone = tz_name
예제 #19
0
class Location(ConfigContainer):
    latitude: float = ConfigEntry(default=0.0, validator=voluptuous.Any(float, int))
    longitude: float = ConfigEntry(default=0.0, validator=voluptuous.Any(float, int))
    elevation: float = ConfigEntry(default=0.0, validator=voluptuous.Any(float, int))

    def __init__(self):
        super().__init__()

        self._astral_location: _astral.LocationInfo
        self.astral_observer: _astral.Observer

    def on_all_values_set(self):
        tz = tzlocal.get_localzone()
        tz_name = str(tz)
        log.debug(f'Local Timezone: {tz_name}')

        # unsure why we need the location in 2.1
        self._astral_location = _astral.LocationInfo(name='HABApp', )
        self._astral_location.latitude = self.latitude
        self._astral_location.longitude = self.longitude
        self._astral_location.timezone = tz_name

        self.astral_observer = self._astral_location.observer
        self.astral_observer.elevation = self.elevation
예제 #20
0
class SmlMqttConfig(ConfigFile):
    mqtt = Mqtt()
    log = Logging()
    general = General()
    devices: List[DeviceConfig] = ConfigEntry(
        default_factory=lambda:
        [{
            'device': 'COM1',
            'timeout': 3,
            'skip': ['value ids that will', 'not be reported']
        }, {
            'device': '/dev/ttyS0',
            'timeout': 3
        }],
        description='Configuration of the sml devices',
        validator=device_validator)
예제 #21
0
class SUB_CONTAINER(ConfigContainer):
    SUB_INT: int = 5
    SUB_FLOAT: float = 5.0
    SUB_FLOAT_COMMENT: float = 5.5
    SUB_MUTABLE_LIST: typing.List[str] = ConfigEntry()
예제 #22
0
 class asdf(ConfigContainer):
     my_int: int = 5
     my_float: float = 3.3
     my_float_comment: float = ConfigEntry(default=5.5, description='testest')
예제 #23
0
 class Test(ConfigFile):
     a = asdf()
     top_level_str: str = 'adsf'
     top_level_entry: float = ConfigEntry(default=5.5, description=' testest')
예제 #24
0
class Subscribe(ConfigContainer):
    qos: int = ConfigEntry(default=0,
                           description='Default QoS for subscribing')
    topics: typing.List[typing.Union[str, int]] = ConfigEntry(
        default_factory=lambda: list(('#', 0)), validator=MqttTopicValidator)
예제 #25
0
class Publish(ConfigContainer):
    qos: int = ConfigEntry(default=0,
                           description='Default QoS when publishing values')
    retain: bool = ConfigEntry(
        default=False,
        description='Default retain flag when publishing values')
예제 #26
0
class General(ConfigContainer):
    listen_only: bool = ConfigEntry(
        False,
        description='If True HABApp will not publish any value to the broker')