def test_default_no_duplicates(self, mock_warn): """Ensure warning on duplicates.""" sen = pysma.Sensors() assert mock_warn.call_count == 0 # Add duplicate frequency news = pysma.Sensor('key1', 'frequency', '') sen.add(news) assert mock_warn.call_count == 1 assert sen[news.name] == news # Add duplicate freq, key should not be raised sen.add(pysma.Sensor('6100_00465700', 'frequency', '')) assert mock_warn.call_count == 2 # Add duplicate freq key only sen.add(pysma.Sensor('6100_00465700', 'f001', '')) assert mock_warn.call_count == 3
def test_null(self): """Test a null or None result.""" sens = pysma.Sensor("6100_40263F00", "s_null", "W") assert (sens.extract_value( {"result": { "_": { "6100_40263F00": { "val": None } } }}) is False) assert sens.value is None assert (sens.extract_value( {"result": { "_": { "6100_40263F00": { "1": [{ "val": None }] } } }}) is False) assert sens.value is None assert sens.extract_value({"result": {"_": {}}}) is False assert sens.value is None
def test_default_no_duplicates(self, mock_warn): """Ensure warning on duplicates.""" sen = pysma.Sensors() assert len(sen) > 25 assert len(sen) < 50 assert mock_warn.call_count == 0 # Add duplicate frequency news = pysma.Sensor("key1", "frequency", "") sen.add(news) assert mock_warn.call_count == 1 assert sen[news.name] == news # Add duplicate freq, key should not be raised sen.add(pysma.Sensor("6100_00465700", "frequency", "")) assert mock_warn.call_count == 2 # Add duplicate freq key only sen.add(pysma.Sensor("6100_00465700", "f001", "")) assert mock_warn.call_count == 3 # Test different key_idx only sen.add(pysma.Sensor("key1_0", "frequency_0", "")) assert mock_warn.call_count == 3 sen.add(pysma.Sensor("key1_1", "frequency_1", "")) assert mock_warn.call_count == 3
def test_null(self): sens = pysma.Sensor('s_null', '6100_40263F00', 'W') assert sens.extract_value( {"result": {"_": {"6100_40263F00": {"val": None}}}}) \ is False assert sens.value is None assert sens.extract_value( {"result": {"_": {"6100_40263F00": {"1": [{"val": None}]}}}}) \ is False assert sens.value is None assert sens.extract_value( {"result": {"_": {}}}) \ is False assert sens.value is None
def _parse_legacy_options(entry: ConfigEntry, sensor_def: pysma.Sensors) -> list[str]: """Parse legacy configuration options. This will parse the legacy CONF_SENSORS and CONF_CUSTOM configuration options to support deprecated yaml config from platform setup. """ # Add sensors from the custom config sensor_def.add( [ pysma.Sensor(o[CONF_KEY], n, o[CONF_UNIT], o[CONF_FACTOR], o.get(CONF_PATH)) for n, o in entry.data.get(CONF_CUSTOM).items() ] ) # Parsing of sensors configuration config_sensors = entry.data.get(CONF_SENSORS) if not config_sensors: return [] # Support import of legacy config that should have been removed from 0.99, but was still functional # See also #25880 and #26306. Functional support was dropped in #48003 if isinstance(config_sensors, dict): config_sensors_list = [] for name, attr in config_sensors.items(): config_sensors_list.append(name) config_sensors_list.extend(attr) config_sensors = config_sensors_list # Find and replace sensors removed from pysma # This only alters the config, the actual sensor migration takes place in _migrate_old_unique_ids for sensor in config_sensors.copy(): if sensor in pysma.LEGACY_MAP: config_sensors.remove(sensor) config_sensors.append(pysma.LEGACY_MAP[sensor]["new_sensor"]) # Only sensors from config should be enabled for sensor in sensor_def: sensor.enabled = sensor.name in config_sensors return config_sensors
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up SMA WebConnect sensor.""" import pysma # Check config again during load - dependency available config = _check_sensor_schema(config) # Init all default sensors sensor_def = pysma.Sensors() # Sensor from the custom config sensor_def.add([ pysma.Sensor(o[CONF_KEY], n, o[CONF_UNIT], o[CONF_FACTOR], o.get(CONF_PATH)) for n, o in config[CONF_CUSTOM].items() ]) # Use all sensors by default config_sensors = config[CONF_SENSORS] if not config_sensors: config_sensors = {s.name: [] for s in sensor_def} # Prepare all HASS sensor entities hass_sensors = [] used_sensors = [] for name, attr in config_sensors.items(): sub_sensors = [sensor_def[s] for s in attr] hass_sensors.append(SMAsensor(sensor_def[name], sub_sensors)) used_sensors.append(name) used_sensors.extend(attr) async_add_entities(hass_sensors) used_sensors = [sensor_def[s] for s in set(used_sensors)] # Init the SMA interface session = async_get_clientsession(hass, verify_ssl=config[CONF_VERIFY_SSL]) grp = config[CONF_GROUP] url = "http{}://{}".format("s" if config[CONF_SSL] else "", config[CONF_HOST]) sma = pysma.SMA(session, url, config[CONF_PASSWORD], group=grp) # Ensure we logout on shutdown async def async_close_session(event): """Close the session.""" await sma.close_session() hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, async_close_session) backoff = 0 backoff_step = 0 async def async_sma(event): """Update all the SMA sensors.""" nonlocal backoff, backoff_step if backoff > 1: backoff -= 1 return values = await sma.read(used_sensors) if not values: try: backoff = [1, 1, 1, 6, 30][backoff_step] backoff_step += 1 except IndexError: backoff = 60 return backoff_step = 0 tasks = [] for sensor in hass_sensors: task = sensor.async_update_values() if task: tasks.append(task) if tasks: await asyncio.wait(tasks) interval = config.get(CONF_SCAN_INTERVAL) or timedelta(seconds=5) async_track_time_interval(hass, async_sma, interval)
def sensors(): """Fixture to create some sensors.""" yield [ (402, True, pysma.Sensor('6400_00262200', 's_402', 'W')), (3514, True, pysma.Sensor('6400_00260100', 's_3514', 'W', 1000)), ]
def sensors(): """Fixture to create some sensors.""" yield [ (402, True, pysma.Sensor("6400_00262200", "s_402", "W")), (3514, True, pysma.Sensor("6400_00260100", "s_3514", "W", 1000)), ]