from typing import Dict, Union from model_data.BaseUtility import Definitions from model_data.epc_attributes.attribute_utils import clean_description, find_keyword class HotWaterAttributes(Definitions): # HEATER_TYPES refer to the main devices used for heating water. These devices can be powered by different energy # sources. HEATER_TYPES = [ 'gas instantaneous', # A water heater that provides hot water only as it is needed 'electric heat pump', # A device that transfers heat from a source (like the ground or air) into a building to provide hot water 'electric immersion', # An electric device that heats water using electric resistance 'gas boiler', # A boiler that uses gas as fuel to heat water 'oil boiler', # A boiler that uses oil as fuel to heat water 'electric instantaneous', # Similar to gas instantaneous, but uses electricity as its energy source 'gas multipoint', # A gas water heater that can supply hot water to multiple points of use at once 'heat pump' # A general category for heat pumps, regardless of the energy source ] # SYSTEM_TYPES refer to the larger system within which the heater operates. SYSTEM_TYPES = [ 'from main system', # The hot water is provided by the main heating system of the building 'from secondary system', # The hot water is provided by a secondary (or supplementary) heating system in the building 'from second main heating system', # Same as 'from secondary system' 'community scheme', # The hot water is provided by a community heating system ] # THERMOSTAT_CHARACTERISTICS refer to features related to temperature control in the system. THERMOSTAT_CHARACTERISTICS = [ 'no cylinder thermostat', # Indicates that the hot water cylinder does not have a thermostat ] # HEATING_SCOPE refers to the specific role of the heater in the heating system. HEATING_SCOPE = [ 'water heating only', # Indicates that the heater is used only for water heating, not space heating ] # ENERGY_RECOVERY refers to systems or epc_attributes that recover and utilize waste energy. ENERGY_RECOVERY = [ 'waste water heat recovery', # A system that recovers heat from waste hot water (e.g., from showers) to preheat incoming cold water 'flue gas heat recovery', # A system that recovers heat from the flue gases of a boiler or furnace ] # TARIFF_TYPE relates to the energy pricing structure or tariff that applies to the system. TARIFF_TYPE = [ 'standard tariff', # The energy used by the system is billed at a standard rate 'off-peak', # The energy used by the system is primarily used during off-peak hours when rates are lower ] # EXTRA_FEATURES are additional features or systems that enhance the efficiency or capability of the hot water # system. EXTRA_FEATURES = [ 'plus solar', # Indicates that the system includes solar thermal panels to assist in water heating ] # CHP_SYSTEMS is specifically for the Combined Heat and Power systems. CHP_SYSTEMS = [ 'chp', # Combined Heat and Power system, a system that simultaneously produces heat and electricity from the same # energy source ] # NO_SYSTEM_PRESENT_KEYWORDS indicates there is no specific hot water system present. NO_SYSTEM_PRESENT_KEYWORDS = [ 'no system present', ] # DISTRIBUTION_SYSTEM_KEYWORDS refers to components that assist in the distribution of the heated water. DISTRIBUTION_SYSTEM_KEYWORDS = [ 'circulator', # A pump used to circulate hot water in the system ] # Indicate if the information is assumed ASSUMED = [ 'assumed' ] # in some rare instances, especially in older homes, a range cooker can be part of a larger system that also # includes a boiler for heating water. In these cases, the cooker may help to heat the water, but this setup is # not common, especially in modern homes. APPLIANCE_SYSTEMS = [ 'gas range cooker', # A gas-powered range cooker ] # Descriptions which represent the same thing SYNONYMS = { 'from second main heating system': 'from secondary system', } WELSH_TEXT = { "ogçör brif system": "from main system", } def __init__(self, description: str): self.description: str = clean_description(description.lower()) self.nodata = not description or description in self.DATA_ANOMALY_MATCHES translation = self.WELSH_TEXT.get(self.description) if translation: self.nodata = False self.description = translation if not any( self._keyword_in_description(keywords) for keywords in [ self.HEATER_TYPES, self.SYSTEM_TYPES, self.THERMOSTAT_CHARACTERISTICS, self.HEATING_SCOPE, self.ENERGY_RECOVERY, self.TARIFF_TYPE, self.EXTRA_FEATURES, self.CHP_SYSTEMS, self.NO_SYSTEM_PRESENT_KEYWORDS, self.APPLIANCE_SYSTEMS, ] ): raise ValueError('Invalid description') def _keyword_in_description(self, keywords): return any(keyword in self.description for keyword in keywords) def process(self) -> Dict[str, Union[str, bool]]: if self.nodata: return { "heater_type": None, "system_type": None, "thermostat_characteristics": None, "heating_scope": None, "energy_recovery": None, "tariff_type": None, "extra_features": None, "chp_systems": None, "distribution_system": None, "no_system_present": None, "assumed": None, "appliance": None, } result: Dict[str, Union[str, bool]] = { "heater_type": find_keyword(self.description, self.HEATER_TYPES), "system_type": find_keyword(self.description, self.SYSTEM_TYPES, self.SYNONYMS), "thermostat_characteristics": find_keyword(self.description, self.THERMOSTAT_CHARACTERISTICS), "heating_scope": find_keyword(self.description, self.HEATING_SCOPE), "energy_recovery": find_keyword(self.description, self.ENERGY_RECOVERY), "tariff_type": find_keyword(self.description, self.TARIFF_TYPE), "extra_features": find_keyword(self.description, self.EXTRA_FEATURES), "chp_systems": find_keyword(self.description, self.CHP_SYSTEMS), "distribution_system": find_keyword(self.description, self.DISTRIBUTION_SYSTEM_KEYWORDS), "no_system_present": find_keyword(self.description, self.NO_SYSTEM_PRESENT_KEYWORDS), "appliance": find_keyword(self.description, self.APPLIANCE_SYSTEMS), } assumed_found = find_keyword(self.description, self.ASSUMED) result["assumed"] = True if assumed_found else False return result