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)
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))
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