diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..618347a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,236 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+
+IntelliJ IDEA
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# Home Assistant local development folder
+hass/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/hass-tns-energo.iml b/.idea/hass-tns-energo.iml
new file mode 100644
index 0000000..febadb2
--- /dev/null
+++ b/.idea/hass-tns-energo.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..05773f6
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..cd666f9
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..1f89c1a
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/custom_components/tns_energo/_base.py b/custom_components/tns_energo/_base.py
index 4d536f3..f9b5e94 100644
--- a/custom_components/tns_energo/_base.py
+++ b/custom_components/tns_energo/_base.py
@@ -301,7 +301,6 @@ def __missing__(self, key: str):
_TData = TypeVar("_TData")
_TAccount = TypeVar("_TAccount", bound="Account")
-
SupportedServicesType = Mapping[
Optional[Tuple[type, SupportsInt]],
Mapping[str, Union[dict, Callable[[dict], dict]]],
@@ -313,6 +312,8 @@ class TNSEnergoEntity(Entity, Generic[_TAccount]):
_supported_services: ClassVar[SupportedServicesType] = {}
+ _attr_should_poll = False
+
@property
def entity_id_prefix(self) -> str:
return f"tns_{self._account.api.region}_{self._account.code}"
@@ -391,14 +392,6 @@ def name_format(self) -> str:
# Base overrides
#################################################################################
- @property
- def should_poll(self) -> bool:
- """Return True if entity has to be polled for state.
-
- False if entity pushes its state to HA.
- """
- return False
-
@property
def device_state_attributes(self):
"""Return the attribute(s) of the sensor"""
@@ -561,11 +554,6 @@ def code(self) -> str:
def state(self) -> StateType:
raise NotImplementedError
- @property
- @abstractmethod
- def icon(self) -> str:
- raise NotImplementedError
-
@property
@abstractmethod
def sensor_related_attributes(self) -> Optional[Mapping[str, Any]]:
@@ -581,11 +569,6 @@ def name_format_values(self) -> Mapping[str, Any]:
def unique_id(self) -> str:
raise NotImplementedError
- @property
- @abstractmethod
- def device_class(self) -> Optional[str]:
- raise NotImplementedError
-
def register_supported_services(self, for_object: Optional[Any] = None) -> None:
for type_feature, services in self._supported_services.items():
result, features = (
diff --git a/custom_components/tns_energo/sensor.py b/custom_components/tns_energo/sensor.py
index a071d4f..3c83bce 100644
--- a/custom_components/tns_energo/sensor.py
+++ b/custom_components/tns_energo/sensor.py
@@ -4,6 +4,7 @@
"""
import logging
import re
+from abc import ABC
from datetime import datetime
from typing import (
Any,
@@ -22,6 +23,7 @@
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
+from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
@@ -79,7 +81,6 @@
RE_HTML_TAGS = re.compile(r"<[^<]+?>")
RE_MULTI_SPACES = re.compile(r"\s{2,}")
-
INDICATIONS_MAPPING_SCHEMA = vol.Schema(
{
vol.Required(vol.Match(r"t\d+")): cv.positive_float,
@@ -91,7 +92,6 @@
lambda x: dict(map(lambda y: ("t" + str(y[0]), y[1]), enumerate(x, start=1))),
)
-
CALCULATE_PUSH_INDICATIONS_SCHEMA = vol.All(
cv.make_entity_service_schema(
{
@@ -145,11 +145,19 @@ def get_supported_features(from_services: SupportedServicesType, for_object: Any
ATTR_METER_CODES: Final = "meter_codes"
-class TNSEnergoAccount(TNSEnergoEntity):
+class TNSEnergoSensor(TNSEnergoEntity, SensorEntity, ABC):
+ pass
+
+
+class TNSEnergoAccount(TNSEnergoSensor):
"""The class for this sensor"""
config_key: ClassVar[str] = CONF_ACCOUNTS
+ _attr_unit_of_measurement = "руб."
+ _attr_icon = "mdi:lightning-bolt-circle"
+ _attr_device_class = DOMAIN + "_account"
+
_supported_services: ClassVar[SupportedServicesType] = {
None: {
SERVICE_GET_PAYMENTS: _SERVICE_SCHEMA_BASE_DATED,
@@ -165,10 +173,6 @@ def __init__(self, *args, **kwargs) -> None:
def code(self) -> str:
return self._account.code
- @property
- def device_class(self) -> Optional[str]:
- return DOMAIN + "_account"
-
@property
def unique_id(self) -> str:
"""Return the unique ID of the sensor"""
@@ -184,14 +188,6 @@ def state(self) -> Union[float, str]:
return 0.0
return balance
- @property
- def icon(self) -> str:
- return "mdi:lightning-bolt-circle"
-
- @property
- def unit_of_measurement(self) -> Optional[str]:
- return "руб."
-
@property
def sensor_related_attributes(self) -> Optional[Mapping[str, Any]]:
account = self._account
@@ -322,11 +318,14 @@ async def async_service_get_payments(self, **call_data):
_LOGGER.info(self.log_prefix + "Finish handling payments retrieval")
-class TNSEnergoMeter(TNSEnergoEntity):
+class TNSEnergoMeter(TNSEnergoSensor):
"""The class for this sensor"""
config_key: ClassVar[str] = CONF_METERS
+ _attr_icon = "mdi:counter"
+ _attr_device_class = DOMAIN + "_meter"
+
_supported_services: ClassVar[SupportedServicesType] = {
None: {
SERVICE_PUSH_INDICATIONS: SERVICE_PUSH_INDICATIONS_SCHEMA,
@@ -405,14 +404,6 @@ def unique_id(self) -> str:
def state(self) -> str:
return self._meter.status or STATE_OK
- @property
- def icon(self):
- return "mdi:counter"
-
- @property
- def device_class(self) -> Optional[str]:
- return DOMAIN + "_meter"
-
@property
def sensor_related_attributes(self) -> Optional[Mapping[str, Any]]:
meter = self._meter
@@ -569,9 +560,13 @@ async def async_service_get_indications(self, **call_data):
_LOGGER.info(self.log_prefix + "Finish handling indications retrieval")
-class TNSEnergoLastPayment(TNSEnergoEntity):
+class TNSEnergoLastPayment(TNSEnergoSensor):
config_key: ClassVar[str] = CONF_LAST_PAYMENT
+ _attr_unit_of_measurement = "руб."
+ _attr_icon = "mdi:cash-multiple"
+ _attr_device_class = DOMAIN + "_payment"
+
def __init__(self, *args, last_payment: Optional[Payment] = None, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._last_payment = last_payment
@@ -623,14 +618,6 @@ def state(self) -> StateType:
return self._last_payment.amount
- @property
- def unit_of_measurement(self) -> str:
- return "руб."
-
- @property
- def icon(self) -> str:
- return "mdi:cash-multiple"
-
@property
def sensor_related_attributes(self) -> Optional[Mapping[str, Any]]:
payment = self._last_payment
@@ -664,10 +651,6 @@ def unique_id(self) -> str:
acc = self._account
return f"{acc.api.__class__.__name__}_lastpayment_{acc.code}"
- @property
- def device_class(self) -> Optional[str]:
- return DOMAIN + "_payment"
-
async_setup_entry = make_common_async_setup_entry(
TNSEnergoAccount,
diff --git a/hacs.json b/hacs.json
index 9b99733..1fc464a 100644
--- a/hacs.json
+++ b/hacs.json
@@ -7,6 +7,6 @@
"sensor"
],
"country": "ru",
- "homeassistant": "2021.4.6",
+ "homeassistant": "2022.3.0",
"iot_class": "Cloud Polling"
}
\ No newline at end of file