python-swidget 1.4.16__tar.gz → 1.4.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-swidget
3
- Version: 1.4.16
3
+ Version: 1.4.17
4
4
  Summary: Python API for Swidget smart devices
5
5
  Home-page: https://github.com/swidget/python-swidget
6
6
  License: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-swidget"
3
- version = "1.4.16"
3
+ version = "1.4.17"
4
4
  description = "Python API for Swidget smart devices"
5
5
  license = "GPL-3.0-or-later"
6
6
  authors = ["Swidget"]
@@ -1004,14 +1004,27 @@ class SwidgetAssembly:
1004
1004
  class SwidgetComponent:
1005
1005
  """Component-level representation of a Swidget Assembly.
1006
1006
 
1007
- Carries the function-state map plus the optional summary-level
1008
- fields fan hosts emit alongside ``functions`` (``maxCFM``, ``code``,
1009
- ``modules``). Non-fan components don't populate them and they stay
1010
- at their defaults.
1007
+ ``summary_functions`` is the immutable list of function tags the
1008
+ device declared in its summary — this is the schema. ``functions``
1009
+ starts as a same-keyed dict of placeholder ``None`` values and is
1010
+ later mutated by ``process_state`` to carry live datapoint values.
1011
+
1012
+ Process_state also leaks in keys that aren't in the summary
1013
+ functions list (e.g. fans emit a ``modules`` map in state that
1014
+ isn't a declared function tag), so ``functions.keys()`` is *not*
1015
+ schema-stable across summary refreshes. Anything that needs a
1016
+ stable schema fingerprint (entity wiring, structure-change
1017
+ detection) must read ``summary_functions``, not ``functions``.
1018
+
1019
+ ``max_cfm``, ``model_code`` and ``modules`` come from the optional
1020
+ summary-level fields fan hosts emit alongside ``functions`` —
1021
+ non-fan components don't populate them.
1011
1022
  """
1012
1023
 
1013
1024
  def __init__(self, component):
1014
- self.functions = {f: None for f in component.get("functions", [])}
1025
+ funcs = list(component.get("functions", []))
1026
+ self.summary_functions: tuple[str, ...] = tuple(funcs)
1027
+ self.functions = {f: None for f in funcs}
1015
1028
  self.max_cfm = component.get("maxCFM")
1016
1029
  self.model_code = component.get("code")
1017
1030
  self.modules = list(component.get("modules", []))