Skip to content

Commit

Permalink
* (Re)send the configuration payload once it changes (e.g. due to
Browse files Browse the repository at this point in the history
  interpolation). The entities are tracked using hash of JSON formatted
  configuration payloads sent, and compared for any change to make a decision
  it should be sent again
+ `EnergomeraConfig`: introduced `_read_config` method dedicated to reading
  configuration file, for ease of mocks during testing
* Better test organization by moving fixtures `mock_serial`, `mock_mqtt`,
  `mock_config` to `conftest.py` and making those configurable via `pytest`
  markers
* `EnergomeraConfig` class no longer requires mocking `patch` built-in,
  since the class now has `_read_config()` method easily mocked
* `test_energomera` no longer generates separate tests for each
   particular MQTT and serial call - those are now validates by single test as
   the whole flow
+ Added tests for handling HomeAssistant configuration payloads, especialy for
  resending those once the payload changes
  • Loading branch information
hostcc committed Apr 28, 2023
1 parent 1186a27 commit 743b6b3
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 1,340 deletions.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ log_cli_level = "error"

markers = [
"mqtt_broker_users",
"serial_simulate_timeout",
"serial_exchange",
"config_yaml"
]

[tool.pylint.main]
Expand Down
35 changes: 21 additions & 14 deletions src/energomera_hass_mqtt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ class IecToHassSensor: # pylint: disable=too-many-instance-attributes

# Class attribute to store HASS sensors having config payload sent, to
# ensure it is done only once per multiple instantiations of the class -
# HASS needs sensor disocvery only once, otherwise logs a message re:
# HASS needs sensor discovery only once, otherwise logs a message re:
# sensor has already been discovered
_hass_config_entities_published = {}
hass_config_payloads_published = {}
# Class attribute defining MQTT topic base for HASS discovery
_mqtt_topic_base = 'sensor'

Expand Down Expand Up @@ -259,15 +259,17 @@ async def process(self, setup_only=False):
if setup_only:
continue

# Send payloads using MQTT
# Send config payload for HomeAssistant discovery only once
# per sensor
if (self._hass_unique_id not in
self._hass_config_entities_published):

# Config payload for sensor discovery
config_payload = self.hass_config_payload()
json_config_payload = json.dumps(config_payload)
# Send configuration payloads using MQTT once per sensor
config_payload = self.hass_config_payload()
json_config_payload = json.dumps(config_payload)
config_payload_sent_hash = (
self.hass_config_payloads_published.get(
self._hass_unique_id, None
)
)
# (re)send the configuration payload once it changes (e.g. due
# to interpolation)
if config_payload_sent_hash != hash(json_config_payload):
_LOGGER.debug("MQTT config payload for HASS"
" auto-discovery: '%s'",
json_config_payload)
Expand All @@ -277,10 +279,10 @@ async def process(self, setup_only=False):
payload=json_config_payload,
retain=True,
)
# Mark the config payload for the given sensor as sent
self._hass_config_entities_published[
# Keep track of JSON formatted configuration payloads sent
self.hass_config_payloads_published[
self._hass_unique_id
] = True
] = hash(json_config_payload)

_LOGGER.debug("Sent HASS config payload to MQTT topic"
" '%s'",
Expand Down Expand Up @@ -459,6 +461,11 @@ def __init__(
self._serial_number = None
self._sw_version = None

# (re)initialize what configuration payloads have been sent across all
# instances of `IecToHassSensor`. Mostly used by tests, as
# `async_main()` instantiates the class only once
IecToHassSensor.hass_config_payloads_published = {}

def iec_read_values(self, address, additional_data=None):
"""
Reads value(s) at selected address from the meter using IEC 62056-21
Expand Down
16 changes: 14 additions & 2 deletions src/energomera_hass_mqtt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ def _get_schema(self):
],
})

@staticmethod
def _read_config(config_file):
"""
Reads configuration file.
:param str config_file: Name of configuration file
:return str: Configuration file contents
"""
with open(config_file, encoding='ascii') as file:
content = file.read()

return content

def __init__(self, config_file=None, content=None):
"""
Initializes configuration state either from file or content string.
Expand All @@ -202,8 +215,7 @@ def __init__(self, config_file=None, content=None):

try:
if not content:
with open(config_file, encoding='ascii') as file:
content = file.read()
content = self._read_config(config_file)

config = yaml.safe_load(content)
except (yaml.YAMLError, OSError) as exc:
Expand Down
Loading

0 comments on commit 743b6b3

Please sign in to comment.