Ejemplo n.º 1
0
def test_get_loader():
    """Test if method returns the preloaded loader object."""
    loader = get_loader()
    assert isinstance(loader, Loader)
    assert loader.char_types is not ({} or None)
    assert loader.serv_types is not ({} or None)

    loader2 = Loader(path_char=CHARACTERISTICS_FILE,
                     path_service=SERVICES_FILE)
    assert loader.char_types == loader2.char_types
    assert loader.serv_types == loader2.serv_types

    assert get_loader() == loader
async def test_supported_states(hass, hk_driver, events):
    """Test different supported states."""
    code = "1234"
    config = {ATTR_CODE: code}
    entity_id = "alarm_control_panel.test"

    loader = get_loader()
    default_current_states = loader.get_char(
        "SecuritySystemCurrentState"
    ).properties.get("ValidValues")
    default_target_services = loader.get_char(
        "SecuritySystemTargetState"
    ).properties.get("ValidValues")

    # Set up a number of test configuration
    test_configs = [
        {
            "features": SUPPORT_ALARM_ARM_HOME,
            "current_values": [
                default_current_states["Disarmed"],
                default_current_states["AlarmTriggered"],
                default_current_states["StayArm"],
            ],
            "target_values": [
                default_target_services["Disarm"],
                default_target_services["StayArm"],
            ],
        },
        {
            "features": SUPPORT_ALARM_ARM_AWAY,
            "current_values": [
                default_current_states["Disarmed"],
                default_current_states["AlarmTriggered"],
                default_current_states["AwayArm"],
            ],
            "target_values": [
                default_target_services["Disarm"],
                default_target_services["AwayArm"],
            ],
        },
        {
            "features": SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY,
            "current_values": [
                default_current_states["Disarmed"],
                default_current_states["AlarmTriggered"],
                default_current_states["StayArm"],
                default_current_states["AwayArm"],
            ],
            "target_values": [
                default_target_services["Disarm"],
                default_target_services["StayArm"],
                default_target_services["AwayArm"],
            ],
        },
        {
            "features": SUPPORT_ALARM_ARM_HOME
            | SUPPORT_ALARM_ARM_AWAY
            | SUPPORT_ALARM_ARM_NIGHT,
            "current_values": [
                default_current_states["Disarmed"],
                default_current_states["AlarmTriggered"],
                default_current_states["StayArm"],
                default_current_states["AwayArm"],
                default_current_states["NightArm"],
            ],
            "target_values": [
                default_target_services["Disarm"],
                default_target_services["StayArm"],
                default_target_services["AwayArm"],
                default_target_services["NightArm"],
            ],
        },
        {
            "features": SUPPORT_ALARM_ARM_HOME
            | SUPPORT_ALARM_ARM_AWAY
            | SUPPORT_ALARM_ARM_NIGHT
            | SUPPORT_ALARM_TRIGGER,
            "current_values": [
                default_current_states["Disarmed"],
                default_current_states["AlarmTriggered"],
                default_current_states["StayArm"],
                default_current_states["AwayArm"],
                default_current_states["NightArm"],
            ],
            "target_values": [
                default_target_services["Disarm"],
                default_target_services["StayArm"],
                default_target_services["AwayArm"],
                default_target_services["NightArm"],
            ],
        },
    ]

    for test_config in test_configs:
        attrs = {"supported_features": test_config.get("features")}

        hass.states.async_set(entity_id, None, attributes=attrs)
        await hass.async_block_till_done()

        acc = SecuritySystem(hass, hk_driver, "SecuritySystem", entity_id, 2, config)
        await acc.run()
        await hass.async_block_till_done()

        valid_current_values = acc.char_current_state.properties.get("ValidValues")
        valid_target_values = acc.char_target_state.properties.get("ValidValues")

        for val in valid_current_values.values():
            assert val in test_config.get("current_values")

        for val in valid_target_values.values():
            assert val in test_config.get("target_values")
    def __init__(self, *args):
        """Initialize a SecuritySystem accessory object."""
        super().__init__(*args, category=CATEGORY_ALARM_SYSTEM)
        state = self.hass.states.get(self.entity_id)
        self._alarm_code = self.config.get(ATTR_CODE)

        supported_states = state.attributes.get(
            ATTR_SUPPORTED_FEATURES,
            (SUPPORT_ALARM_ARM_HOME
             | SUPPORT_ALARM_ARM_AWAY
             | SUPPORT_ALARM_ARM_NIGHT
             | SUPPORT_ALARM_TRIGGER),
        )

        loader = get_loader()
        default_current_states = loader.get_char(
            "SecuritySystemCurrentState").properties.get("ValidValues")
        default_target_services = loader.get_char(
            "SecuritySystemTargetState").properties.get("ValidValues")

        current_supported_states = [
            HASS_TO_HOMEKIT[STATE_ALARM_DISARMED],
            HASS_TO_HOMEKIT[STATE_ALARM_TRIGGERED],
        ]
        target_supported_services = [
            HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_DISARM]
        ]

        if supported_states & SUPPORT_ALARM_ARM_HOME:
            current_supported_states.append(
                HASS_TO_HOMEKIT[STATE_ALARM_ARMED_HOME])
            target_supported_services.append(
                HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_ARM_HOME])

        if supported_states & SUPPORT_ALARM_ARM_AWAY:
            current_supported_states.append(
                HASS_TO_HOMEKIT[STATE_ALARM_ARMED_AWAY])
            target_supported_services.append(
                HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_ARM_AWAY])

        if supported_states & SUPPORT_ALARM_ARM_NIGHT:
            current_supported_states.append(
                HASS_TO_HOMEKIT[STATE_ALARM_ARMED_NIGHT])
            target_supported_services.append(
                HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_ARM_NIGHT])

        new_current_states = {
            key: val
            for key, val in default_current_states.items()
            if val in current_supported_states
        }
        new_target_services = {
            key: val
            for key, val in default_target_services.items()
            if val in target_supported_services
        }

        serv_alarm = self.add_preload_service(SERV_SECURITY_SYSTEM)
        self.char_current_state = serv_alarm.configure_char(
            CHAR_CURRENT_SECURITY_STATE,
            value=HASS_TO_HOMEKIT[STATE_ALARM_DISARMED],
            valid_values=new_current_states,
        )
        self.char_target_state = serv_alarm.configure_char(
            CHAR_TARGET_SECURITY_STATE,
            value=HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_DISARM],
            valid_values=new_target_services,
            setter_callback=self.set_security_state,
        )

        # Set the state so it is in sync on initial
        # GET to avoid an event storm after homekit startup
        self.async_update_state(state)
Ejemplo n.º 4
0
MQTTSERVER = "pi-server" # "192.168.1.132"
accessory_state = expanduser('~/Documents/2. Code/2. Python/HAP-MQTT/accessory.state')

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO,
                    format="[%(asctime)s] [%(module)-16s] [%(levelname)-8s] %(message)s",
                    datefmt="%I:%M:%S %p")

# Start the accessory on port 51826
driver = AccessoryDriver(port=51827,
                         persist_file=accessory_state)

mqtt_bridge = HapMqtt(MQTTSERVER, driver, "mqtt_bridge")

# get loaders
service_loader = loader.get_loader()
char_loader = loader.get_loader()

test = Accessory(driver, "Switch", aid=999196)
test.add_service(service_loader.get_service("Switch"))

accessories = list()
accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_1", aid=1111))
accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_2", aid=2222))
accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_3", aid=3333))
accessories.append(BasicLight("outside", MQTTSERVER, driver, "flood_4", aid=4444))
accessories.append(TemperatureSensor(driver, "fake_temp"))


# accessories.append(test)
# MqttAccessories(TemperatureSensor(MQTTSERVER, driver, "Battery_1", aid=2323))
Ejemplo n.º 5
0
    def load_accessories(self, override_ids=False):
        """
        Return a list of initialized accessories specified by the config files.

        The characteristics of those accessories should contain three additional
        values: topic_in, topic_out and adapter used by the MqttBridge class.

        :param override_ids: override accessory ids for a new bridge config
        :type override_ids: bool
        """
        # find all cfg files, but skip the bridge.cfg
        fnames = []
        for r, _, fs in os.walk(self.cfg_path):
            fnames += [
                os.path.join(r, f) for f in fs
                if f != 'bridge.cfg' and f != 'accessory.state'
            ]

        for fname in fnames:
            cfg = configparser.ConfigParser()
            cfg.optionxform = str
            cfg.fname = fname

            try:
                cfg.read(fname)
                self.cfgs.append(cfg)
            except Exception as e:
                logger.warn('Skipping "{}" because of Exception: {}'.format(
                    fname, str(e)))

        # sort by aid
        max_aid = 2**63 - 1
        self.cfgs = sorted(
            self.cfgs,
            key=lambda cfg: int(cfg['Accessory'].get('AID', max_aid)))

        self.accs = []
        for cfg in self.cfgs:
            try:
                # init accessory
                acc_def = cfg['Accessory']
                if acc_def['Category'] not in categories:
                    logger.warn('Unknown category: "{}"'.format(
                        acc_def['category']))
                    continue
                if 'DisplayName' not in acc_def.keys():
                    # use filename as display name
                    acc_def['DisplayName'] = os.path.basename(fname).split(
                        '.')[0]

                aid = None
                if not override_ids:
                    aid = acc_def.get('AID', None)
                if aid is not None:
                    aid = int(aid)

                acc = Accessory(self.driver, acc_def['DisplayName'], aid=aid)
                acc.category = categories[acc_def.get('Category', 'Other')]

                acc.set_info_service(acc_def.get('FirmwareRevision', None),
                                     acc_def.get('Manufacturer', None),
                                     acc_def.get('Model', None),
                                     acc_def.get('SerialNumber', None))

                # init services
                serv_types = cfg.sections()
                serv_types.remove('Accessory')
                for serv_type in serv_types:
                    serv_def = cfg[serv_type]
                    serv = loader.get_loader().get_service(serv_type)
                    char_types = serv_def.keys()

                    for char_type in char_types:
                        char_def = serv_def[char_type]
                        char_def = char_def.split()

                        # init characteristic
                        try:
                            char = loader.get_loader().get_char(char_type)

                            if len(char_def) != 3:
                                logger.warn(
                                    'Skipping caracteristic "{}" because of invalid format'
                                    .format(char_type))
                                continue

                            # add topics and adapter
                            char.properties['topic_in'] = None
                            char.properties['topic_out'] = None
                            char.properties['adapter'] = None

                            if char_def[0] != '_':
                                char.properties['topic_in'] = char_def[0]
                            if char_def[1] != '_':
                                char.properties['topic_out'] = char_def[1]
                            if char_def[2] != '_':
                                char.properties['adapter'] = char_def[2]

                            # add characteristic
                            added = False
                            for i, old_char in enumerate(serv.characteristics):
                                if old_char.type_id == char.type_id:
                                    serv.characteristics[i] = char
                                    added = True
                                    break

                            if not added:
                                serv.add_characteristic(char)

                        except KeyError as e:
                            continue

                    acc.add_service(serv)

                self.accs.append(acc)
                logger.info('Added accessory "{}"'.format(acc.display_name))

            except Exception as e:
                logger.warn(
                    'Skipping "{}" because of Exception: {}: {}'.format(
                        type(e), cfg.fname, str(e)))

        return self.accs