hvx 0.5.0__py3-none-any.whl

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.
Files changed (127) hide show
  1. hvx/__init__.py +27 -0
  2. hvx/__main__.py +7 -0
  3. hvx/app/__init__.py +7 -0
  4. hvx/app/analysis_runner.py +102 -0
  5. hvx/app/api.py +1030 -0
  6. hvx/app/main.py +345 -0
  7. hvx/app/state.py +270 -0
  8. hvx/building_csv.py +214 -0
  9. hvx/cli.py +349 -0
  10. hvx/connectors/__init__.py +3 -0
  11. hvx/connectors/climify.py +188 -0
  12. hvx/connectors/csv/__init__.py +29 -0
  13. hvx/connectors/csv/config.yaml +7 -0
  14. hvx/connectors/csv/data_loader.py +496 -0
  15. hvx/connectors/csv/portfolio_loader.py +850 -0
  16. hvx/connectors/dmi.py +124 -0
  17. hvx/core/__init__.py +257 -0
  18. hvx/core/access.py +80 -0
  19. hvx/core/aggregators.py +77 -0
  20. hvx/core/analysis.py +182 -0
  21. hvx/core/config/__init__.py +26 -0
  22. hvx/core/config/loader.py +74 -0
  23. hvx/core/data_quality.py +487 -0
  24. hvx/core/energy.py +451 -0
  25. hvx/core/energy_pricing.py +217 -0
  26. hvx/core/entities.py +2309 -0
  27. hvx/core/enums/__init__.py +52 -0
  28. hvx/core/enums/access.py +31 -0
  29. hvx/core/enums/analysis.py +49 -0
  30. hvx/core/enums/country.py +245 -0
  31. hvx/core/enums/energy.py +62 -0
  32. hvx/core/enums/rules.py +46 -0
  33. hvx/core/enums/sensors.py +96 -0
  34. hvx/core/enums/spatial.py +103 -0
  35. hvx/core/enums/timeseries.py +118 -0
  36. hvx/core/filters/__init__.py +17 -0
  37. hvx/core/filters/opening_hours_filter.py +117 -0
  38. hvx/core/filters/seasonal_filter.py +295 -0
  39. hvx/core/filters/time_filter.py +221 -0
  40. hvx/core/metering.py +310 -0
  41. hvx/core/py.typed +0 -0
  42. hvx/core/rules.py +161 -0
  43. hvx/core/schedules.py +322 -0
  44. hvx/core/semantics/__init__.py +57 -0
  45. hvx/core/semantics/brick.py +605 -0
  46. hvx/core/semantics/ieq.py +294 -0
  47. hvx/core/semantics/ifc.py +281 -0
  48. hvx/core/semantics/ifc_guid.py +69 -0
  49. hvx/core/semantics/mappings.py +254 -0
  50. hvx/core/semantics/namespaces.py +62 -0
  51. hvx/core/semantics/ontology/hvx_ieq.ttl +174 -0
  52. hvx/core/semantics/types.py +37 -0
  53. hvx/core/simulation.py +80 -0
  54. hvx/core/spacial_entity.py +1013 -0
  55. hvx/core/standards_registry.py +410 -0
  56. hvx/core/timeseries_aggregator.py +318 -0
  57. hvx/core/utils/calendar.py +55 -0
  58. hvx/live/__init__.py +41 -0
  59. hvx/live/base.py +106 -0
  60. hvx/live/bindings.py +79 -0
  61. hvx/live/chirpstack.py +373 -0
  62. hvx/live/limits.py +106 -0
  63. hvx/live/monitor.py +249 -0
  64. hvx/live/site.py +285 -0
  65. hvx/live/sources.py +171 -0
  66. hvx/mcp_server.py +421 -0
  67. hvx/reporting/__init__.py +77 -0
  68. hvx/reporting/aggregate.py +194 -0
  69. hvx/reporting/analysis.py +565 -0
  70. hvx/reporting/branding.py +102 -0
  71. hvx/reporting/brands/baw.yaml +18 -0
  72. hvx/reporting/builder.py +219 -0
  73. hvx/reporting/charts.py +480 -0
  74. hvx/reporting/config.py +158 -0
  75. hvx/reporting/frames.py +170 -0
  76. hvx/reporting/i18n.py +304 -0
  77. hvx/reporting/model.py +216 -0
  78. hvx/reporting/renderers/__init__.py +68 -0
  79. hvx/reporting/renderers/html.py +148 -0
  80. hvx/reporting/renderers/pdf.py +86 -0
  81. hvx/reporting/renderers/tabular.py +96 -0
  82. hvx/reporting/templates/report.html.j2 +531 -0
  83. hvx/simulations/__init__.py +50 -0
  84. hvx/simulations/config/__init__.py +22 -0
  85. hvx/simulations/config/registry.py +177 -0
  86. hvx/simulations/models/__init__.py +37 -0
  87. hvx/simulations/models/correlations/__init__.py +19 -0
  88. hvx/simulations/models/correlations/model.py +145 -0
  89. hvx/simulations/models/correlations/seasonal_thermal_analysis.py +198 -0
  90. hvx/simulations/models/correlations/solar_gain_analysis.py +291 -0
  91. hvx/simulations/models/occupancy/__init__.py +11 -0
  92. hvx/simulations/models/occupancy/config.yaml +77 -0
  93. hvx/simulations/models/occupancy/model.py +241 -0
  94. hvx/simulations/models/rc_thermal/__init__.py +13 -0
  95. hvx/simulations/models/rc_thermal/config.yaml +94 -0
  96. hvx/simulations/models/rc_thermal/model.py +347 -0
  97. hvx/simulations/models/real_epc/__init__.py +10 -0
  98. hvx/simulations/models/real_epc/config.yaml +57 -0
  99. hvx/simulations/models/real_epc/model.py +72 -0
  100. hvx/simulations/models/recommendations/__init__.py +20 -0
  101. hvx/simulations/models/recommendations/model.py +439 -0
  102. hvx/simulations/models/reporting/__init__.py +18 -0
  103. hvx/simulations/models/reporting/html_report_service.py +84 -0
  104. hvx/simulations/models/reporting/json_export_service.py +613 -0
  105. hvx/simulations/models/scenario/__init__.py +14 -0
  106. hvx/simulations/models/scenario/model.py +190 -0
  107. hvx/simulations/models/ventilation/__init__.py +11 -0
  108. hvx/simulations/models/ventilation/config.yaml +75 -0
  109. hvx/simulations/models/ventilation/model.py +198 -0
  110. hvx/simulations/registry.py +267 -0
  111. hvx/standards/__init__.py +4 -0
  112. hvx/standards/br18/analysis.py +288 -0
  113. hvx/standards/br18/config.yaml +234 -0
  114. hvx/standards/en16798/analysis.py +1499 -0
  115. hvx/standards/en16798/config.yaml +294 -0
  116. hvx/standards/tail/aggregate.py +83 -0
  117. hvx/standards/tail/analysis.py +350 -0
  118. hvx/standards/tail/calculator.py +1141 -0
  119. hvx/standards/tail/config.yaml +358 -0
  120. hvx/standards/tail/docs/TAIL_algorithm.txt +111 -0
  121. hvx/tail_label.py +303 -0
  122. hvx-0.5.0.dist-info/METADATA +509 -0
  123. hvx-0.5.0.dist-info/RECORD +127 -0
  124. hvx-0.5.0.dist-info/WHEEL +5 -0
  125. hvx-0.5.0.dist-info/entry_points.txt +2 -0
  126. hvx-0.5.0.dist-info/licenses/LICENSE +373 -0
  127. hvx-0.5.0.dist-info/top_level.txt +1 -0
hvx/__init__.py ADDED
@@ -0,0 +1,27 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ """
5
+ HVX — indoor environmental quality (IEQ) analytics for buildings.
6
+
7
+ Subpackages
8
+ -----------
9
+ ``hvx.core`` data model (Portfolio / Building / Floor / Room), IFC & Brick semantics
10
+ ``hvx.standards`` EN 16798-1, TAIL, BR18 assessments
11
+ ``hvx.simulations`` ventilation, occupancy, correlations, scenarios, recommendations
12
+ ``hvx.reporting`` portfolio reports (HTML / JSON / CSV)
13
+ ``hvx.live`` live data sources (Home Assistant, HTTP, in-memory) and rolling monitoring
14
+ ``hvx.connectors`` file loaders (CSV)
15
+ ``hvx.app`` FastAPI backend and Streamlit UI (optional extras)
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from importlib.metadata import PackageNotFoundError, version
21
+
22
+ try:
23
+ __version__ = version("hvx")
24
+ except PackageNotFoundError: # running from a source checkout
25
+ __version__ = "0.0.0+local"
26
+
27
+ __all__ = ["__version__"]
hvx/__main__.py ADDED
@@ -0,0 +1,7 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ from hvx.cli import cli
5
+
6
+ if __name__ == "__main__":
7
+ cli()
hvx/app/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ """
5
+ Streamlit application package for interactive portfolio management.
6
+ """
7
+
@@ -0,0 +1,102 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ from __future__ import annotations
5
+
6
+ from typing import Dict, Iterable, Optional
7
+
8
+ import pandas as pd
9
+
10
+ from hvx.core import (
11
+ Room,
12
+ Building,
13
+ generate_occupancy_mask,
14
+ get_opening_profile_for_building_type,
15
+ )
16
+ from hvx.core.utils.calendar import get_holiday_dates
17
+ from hvx.standards.en16798.analysis import EN16798Calculator, VentilationType as ENVentilationType
18
+
19
+
20
+ def _room_dataframe(room: Room) -> Optional[pd.DataFrame]:
21
+ if not room.timeseries_data:
22
+ return None
23
+ df = pd.DataFrame(room.timeseries_data)
24
+ if room.timestamps and len(room.timestamps) == len(df.index):
25
+ idx = pd.to_datetime(room.timestamps, errors="coerce")
26
+ df.index = idx
27
+ df = df[~df.index.isna()]
28
+ elif "timestamp" in df.columns:
29
+ idx = pd.to_datetime(df["timestamp"], errors="coerce")
30
+ df = df.drop(columns=["timestamp"])
31
+ df.index = idx
32
+ df = df[~df.index.isna()]
33
+ else:
34
+ df.index = pd.RangeIndex(len(df))
35
+ if df.empty:
36
+ return None
37
+ return df
38
+
39
+
40
+ def run_en16798_for_room(
41
+ room: Room,
42
+ season: str = "heating",
43
+ building: Optional[Building] = None,
44
+ ) -> Optional[Dict]:
45
+ df = _room_dataframe(room)
46
+ if df is None:
47
+ return None
48
+
49
+ occupancy_mask: Optional[pd.Series] = None
50
+ if isinstance(df.index, pd.DatetimeIndex):
51
+ building_type = getattr(building, "building_type", None)
52
+ profile = get_opening_profile_for_building_type(
53
+ building_type.lower() if isinstance(building_type, str) else building_type
54
+ )
55
+ holiday_dates = get_holiday_dates(getattr(building, "country", None))
56
+ occupancy_mask = generate_occupancy_mask(df.index, profile, holiday_dates=holiday_dates)
57
+ df = df[occupancy_mask]
58
+
59
+ if df.empty:
60
+ return None
61
+
62
+ temperature = df["temperature"] if "temperature" in df else None
63
+ co2 = df["co2"] if "co2" in df else None
64
+ humidity = df["humidity"] if "humidity" in df else None
65
+
66
+ ventilation_type = ENVentilationType.MECHANICAL
67
+ if room.ventilation_type:
68
+ try:
69
+ ventilation_type = ENVentilationType(room.ventilation_type.value)
70
+ except ValueError:
71
+ ventilation_type = ENVentilationType.MECHANICAL
72
+
73
+ results = EN16798Calculator.assess_timeseries_compliance(
74
+ temperature=temperature,
75
+ co2=co2,
76
+ humidity=humidity,
77
+ season=season,
78
+ ventilation_type=ventilation_type,
79
+ )
80
+ return results
81
+
82
+
83
+ def run_en16798_for_rooms(
84
+ rooms: Iterable[Room],
85
+ season: str = "heating",
86
+ buildings: Optional[Dict[str, Building]] = None,
87
+ ) -> Dict[str, Dict]:
88
+ summaries: Dict[str, Dict] = {}
89
+ for room in rooms:
90
+ building_obj = None
91
+ if buildings:
92
+ if room.building_id and room.building_id in buildings:
93
+ building_obj = buildings.get(room.building_id)
94
+ else:
95
+ for parent_id in room.parent_ids:
96
+ if parent_id in buildings:
97
+ building_obj = buildings[parent_id]
98
+ break
99
+ result = run_en16798_for_room(room, season=season, building=building_obj)
100
+ if result:
101
+ summaries[room.id] = result
102
+ return summaries