async def main_loop(loop, password, user, ip): # pylint: disable=invalid-name """Main loop.""" async with aiohttp.ClientSession( loop=loop, connector=aiohttp.TCPConnector(ssl=False)) as session: VAR["sma"] = pysma.SMA(session, ip, password=password, group=user) await VAR["sma"].new_session() if VAR["sma"].sma_sid is None: _LOGGER.info("No session ID") return _LOGGER.info("NEW SID: %s", VAR["sma"].sma_sid) VAR["running"] = True cnt = 5 sensors = pysma.Sensors() while VAR.get("running"): await VAR["sma"].read(sensors) print_table(sensors) send_table(sensors) cnt -= 1 if cnt == 0: break await asyncio.sleep(2) await VAR["sma"].close_session()
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 _check_sensor_schema(conf): """Check sensors and attributes are valid.""" try: valid = [s.name for s in pysma.Sensors()] except (ImportError, AttributeError): return conf customs = list(conf[CONF_CUSTOM].keys()) for sensor in conf[CONF_SENSORS]: if sensor in customs: _LOGGER.warning( "All custom sensors will be added automatically, no need to include them in sensors: %s", sensor, ) elif sensor not in valid: raise vol.Invalid(f"{sensor} does not exist") return conf
def _check_sensor_schema(conf): """Check sensors and attributes are valid.""" try: import pysma valid = [s.name for s in pysma.Sensors()] except (ImportError, AttributeError): return conf for name in conf[CONF_CUSTOM]: valid.append(name) for sname, attrs in conf[CONF_SENSORS].items(): if sname not in valid: raise vol.Invalid("{} does not exist".format(sname)) for attr in attrs: if attr in valid: continue raise vol.Invalid("{} does not exist [{}]".format(attr, sname)) return conf
def _check_sensor_schema(conf): """Check sensors and attributes are valid.""" try: import pysma valid = [s.name for s in pysma.Sensors()] except (ImportError, AttributeError): return conf customs = list(conf[CONF_CUSTOM].keys()) if isinstance(conf[CONF_SENSORS], dict): msg = '"sensors" should be a simple list from 0.99' if OLD_CONFIG_DEPRECATED: raise vol.Invalid(msg) _LOGGER.warning(msg) valid.extend(customs) for sname, attrs in conf[CONF_SENSORS].items(): if sname not in valid: raise vol.Invalid("{} does not exist".format(sname)) if attrs: _LOGGER.warning( "Attributes on sensors will be deprecated in 0.99. Start using only individual sensors: %s: %s", sname, ", ".join(attrs), ) for attr in attrs: if attr in valid: continue raise vol.Invalid("{} does not exist [{}]".format(attr, sname)) return conf # Sensors is a list (only option from from 0.99) for sensor in conf[CONF_SENSORS]: if sensor in customs: _LOGGER.warning( "All custom sensors will be added automatically, no need to include them in sensors: %s", sensor, ) elif sensor not in valid: raise vol.Invalid("{} does not exist".format(sensor)) return conf
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
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 test_default_jmes(self, mock_warn): """Ensure default sensors are ok.""" sens = pysma.Sensors() for sen in sens: sen.extract_value(SB_1_5) assert mock_warn.called
def test_type_error(self, mock_warn): """Ensure TypeError on not isinstance.""" sen = pysma.Sensors() with pytest.raises(TypeError): sen.add("This is not a Sensor")
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up sma from a config entry.""" # Init all default sensors sensor_def = pysma.Sensors() if entry.source == SOURCE_IMPORT: config_sensors = _parse_legacy_options(entry, sensor_def) _migrate_old_unique_ids(hass, entry, sensor_def, config_sensors) # Init the SMA interface protocol = "https" if entry.data[CONF_SSL] else "http" url = f"{protocol}://{entry.data[CONF_HOST]}" verify_ssl = entry.data[CONF_VERIFY_SSL] group = entry.data[CONF_GROUP] password = entry.data[CONF_PASSWORD] session = async_get_clientsession(hass, verify_ssl=verify_ssl) sma = pysma.SMA(session, url, password, group) # Define the coordinator async def async_update_data(): """Update the used SMA sensors.""" values = await sma.read(sensor_def) if not values: raise UpdateFailed interval = timedelta( seconds=entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) ) coordinator = DataUpdateCoordinator( hass, _LOGGER, name="sma", update_method=async_update_data, update_interval=interval, ) try: await coordinator.async_config_entry_first_refresh() except ConfigEntryNotReady: await sma.close_session() raise # Ensure we logout on shutdown async def async_close_session(event): """Close the session.""" await sma.close_session() remove_stop_listener = hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STOP, async_close_session ) hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = { PYSMA_OBJECT: sma, PYSMA_COORDINATOR: coordinator, PYSMA_SENSORS: sensor_def, PYSMA_REMOVE_LISTENER: remove_stop_listener, } hass.config_entries.async_setup_platforms(entry, PLATFORMS) return True