def validate_infinite_bus(**kwargs): validate_commercial_producer(**kwargs) if "energy_rate_profile" in kwargs and kwargs["energy_rate_profile"] is not None and \ ("energy_rate_profile_uuid" not in kwargs or kwargs["energy_rate_profile_uuid"] is None): raise D3ADeviceException( {"misconfiguration": [f"energy_rate_profile must have a uuid."]}) if key_in_dict_and_not_none_and_not_str_type(kwargs, "energy_rate_profile_uuid"): raise D3ADeviceException({ "misconfiguration": [f"energy_rate_profile_uuid must have a string type."] }) if key_in_dict_and_not_none(kwargs, "energy_buy_rate"): _validate_rate(kwargs['energy_buy_rate']) if key_in_dict_and_not_none(kwargs, "buying_rate_profile") and \ ("buying_rate_profile_uuid" not in kwargs or kwargs["buying_rate_profile_uuid"] is None): raise D3ADeviceException( {"misconfiguration": [f"buying_rate_profile must have a uuid."]}) if key_in_dict_and_not_none_and_not_str_type(kwargs, "buying_rate_profile_uuid"): raise D3ADeviceException({ "misconfiguration": [f"buying_rate_profile_uuid must have a string type."] })
def validate_pv_device_price(**kwargs): if "final_selling_rate" in kwargs and kwargs[ "final_selling_rate"] is not None: error_message = { "misconfiguration": [ f"final_selling_rate should be in between " f"{PvSettings.FINAL_SELLING_RATE_LIMIT.min} & " f"{PvSettings.FINAL_SELLING_RATE_LIMIT.max}" ] } validate_range_limit(PvSettings.FINAL_SELLING_RATE_LIMIT.min, kwargs["final_selling_rate"], PvSettings.FINAL_SELLING_RATE_LIMIT.max, error_message) if "initial_selling_rate" in kwargs and kwargs[ "initial_selling_rate"] is not None: error_message = { "misconfiguration": [ f"initial_selling_rate should be in between " f"{PvSettings.INITIAL_SELLING_RATE_LIMIT.min} & " f"{PvSettings.INITIAL_SELLING_RATE_LIMIT.max}" ] } validate_range_limit(PvSettings.INITIAL_SELLING_RATE_LIMIT.min, kwargs["initial_selling_rate"], PvSettings.INITIAL_SELLING_RATE_LIMIT.max, error_message) if ("initial_selling_rate" in kwargs and kwargs["initial_selling_rate"] is not None) and \ ("final_selling_rate" in kwargs and kwargs["final_selling_rate"] is not None) and \ (kwargs["initial_selling_rate"] < kwargs["final_selling_rate"]): raise D3ADeviceException({ "misconfiguration": [ f"initial_selling_rate/market_maker_rate should be greater " f"than or equal to final_selling_rate. Please adapt the " f"market_maker_rate of the configuration or the " f"initial_selling_rate" ] }) if ("fit_to_limit" in kwargs and kwargs["fit_to_limit"] is True) and \ ("energy_rate_decrease_per_update" in kwargs and kwargs["energy_rate_decrease_per_update"] is not None): raise D3ADeviceException({ "misconfiguration": [ f"fit_to_limit & energy_rate_decrease_per_update " f"can't be set together." ] }) if "energy_rate_decrease_per_update" in kwargs and \ kwargs["energy_rate_decrease_per_update"] is not None: error_message = \ {"misconfiguration": [f"energy_rate_decrease_per_update should be in between " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min} & " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max}"]} validate_range_limit(GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min, kwargs["energy_rate_decrease_per_update"], GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max, error_message)
def __init__( self, panel_count: int = 1, initial_selling_rate: float = ConstSettings.GeneralSettings. DEFAULT_MARKET_MAKER_RATE, final_selling_rate: float = ConstSettings.PVSettings. FINAL_SELLING_RATE, fit_to_limit: bool = True, update_interval=duration( minutes=ConstSettings.GeneralSettings.DEFAULT_UPDATE_INTERVAL), energy_rate_decrease_per_update: float = ConstSettings. GeneralSettings.ENERGY_RATE_DECREASE_PER_UPDATE, max_panel_power_W: float = None, use_market_maker_rate: bool = False): """ :param panel_count: Number of solar panels for this PV plant :param initial_selling_rate: Upper Threshold for PV offers :param final_selling_rate: Lower Threshold for PV offers :param fit_to_limit: Linear curve following initial_selling_rate & initial_selling_rate :param update_interval: Interval after which PV will update its offer :param energy_rate_decrease_per_update: Slope of PV Offer change per update :param max_panel_power_W: """ # If use_market_maker_rate is true, overwrite initial_selling_rate to market maker rate if use_market_maker_rate: initial_selling_rate = GlobalConfig.market_maker_rate try: validate_pv_device(panel_count=panel_count, max_panel_power_W=max_panel_power_W) except D3ADeviceException as e: raise D3ADeviceException(str(e)) if isinstance(update_interval, int): update_interval = duration(minutes=update_interval) BaseStrategy.__init__(self) self.offer_update = UpdateFrequencyMixin( initial_selling_rate, final_selling_rate, fit_to_limit, energy_rate_decrease_per_update, update_interval) for time_slot in generate_market_slot_list(): try: validate_pv_device( initial_selling_rate=self.offer_update. initial_rate[time_slot], final_selling_rate=self.offer_update.final_rate[time_slot]) except D3ADeviceException as e: raise D3ADeviceException(str(e)) self.panel_count = panel_count self.final_selling_rate = final_selling_rate self.max_panel_power_W = max_panel_power_W self.energy_production_forecast_kWh = {} # type: Dict[Time, float] self.state = PVState()
def validate_market_maker(**kwargs): validate_energy_rate(**kwargs) if "energy_rate_profile" in kwargs and kwargs["energy_rate_profile"] is not None and \ ("energy_rate_profile_uuid" not in kwargs or kwargs["energy_rate_profile_uuid"] is None): raise D3ADeviceException( {"misconfiguration": [f"energy_rate_profile must have a uuid."]}) if "grid_connected" in kwargs and kwargs["grid_connected"] is not None and \ not isinstance(kwargs["grid_connected"], bool): raise D3ADeviceException( {"misconfiguration": [f"grid_connected must be a boolean value."]})
def validate_finite_diesel_generator(**kwargs): if "max_available_power_kW" in kwargs and kwargs[ "max_available_power_kW"] is not None: if isinstance(kwargs["max_available_power_kW"], (int, float)): error_message = \ {"misconfiguration": [f"max_available_power_kW should be in between " f"{CepSettings.MAX_POWER_KW_LIMIT.min} & " f"{CepSettings.MAX_POWER_KW_LIMIT.max}."]} validate_range_limit(CepSettings.MAX_POWER_KW_LIMIT.min, kwargs["max_available_power_kW"], CepSettings.MAX_POWER_KW_LIMIT.max, error_message) elif isinstance(kwargs["max_available_power_kW"], dict): error_message = \ {"misconfiguration": [f"max_available_power_kW should be in between " f"{CepSettings.MAX_POWER_KW_LIMIT.min} & " f"{CepSettings.MAX_POWER_KW_LIMIT.max}."]} for date, value in kwargs["max_available_power_kW"].items(): validate_range_limit(CepSettings.MAX_POWER_KW_LIMIT.min, value, CepSettings.MAX_POWER_KW_LIMIT.max, error_message) else: raise D3ADeviceException({ "misconfiguration": [f"max_available_power_kW has an " f"invalid type. "] }) validate_commercial_producer(**kwargs)
def validate_pv_device_energy(**kwargs): if "panel_count" in kwargs and kwargs["panel_count"] is not None: error_message = \ {"misconfiguration": [f"PV panel count should be in between " f"{PvSettings.PANEL_COUNT_LIMIT.min} & " f"{PvSettings.PANEL_COUNT_LIMIT.max}"]} validate_range_limit(PvSettings.PANEL_COUNT_LIMIT.min, kwargs["panel_count"], PvSettings.PANEL_COUNT_LIMIT.max, error_message) if "max_panel_power_W" in kwargs and kwargs[ "max_panel_power_W"] is not None: error_message = \ {"misconfiguration": [f"max_panel_power_W should be in between " f"{PvSettings.MAX_PANEL_OUTPUT_W_LIMIT.min} & " f"{PvSettings.MAX_PANEL_OUTPUT_W_LIMIT.max}"]} validate_range_limit(PvSettings.MAX_PANEL_OUTPUT_W_LIMIT.min, kwargs["max_panel_power_W"], PvSettings.MAX_PANEL_OUTPUT_W_LIMIT.max, error_message) if "cloud_coverage" in kwargs and kwargs["cloud_coverage"] is not None: if (kwargs["cloud_coverage"] != 4) and \ ("power_profile" in kwargs and kwargs["power_profile"] is not None): raise D3ADeviceException({ "misconfiguration": [ f"cloud_coverage (if values 0-3) & " f"power_profile can't be set together." ] })
def validate_energy_rate(**kwargs): if "energy_rate" in kwargs and kwargs["energy_rate"] is not None: if isinstance(kwargs["energy_rate"], (float, int)): _validate_rate(kwargs["energy_rate"]) elif isinstance(kwargs["energy_rate"], str): _validate_rate_profile(ast.literal_eval(kwargs["energy_rate"])) elif isinstance(kwargs["energy_rate"], dict): _validate_rate_profile(kwargs["energy_rate"]) else: raise D3ADeviceException( {"misconfiguration": [f"energy_rate has an invalid type."]})
def area_reconfigure_event(self, **kwargs): assert all(k in self.parameters for k in kwargs.keys()) try: validate_pv_device(**kwargs) except D3ADeviceException as e: raise D3ADeviceException(str(e)) for name, value in kwargs.items(): setattr(self, name, value) if 'initial_selling_rate' in kwargs and kwargs[ 'initial_selling_rate'] is not None: self.offer_update.initial_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['initial_selling_rate']) if 'final_selling_rate' in kwargs and kwargs[ 'final_selling_rate'] is not None: self.offer_update.final_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['final_selling_rate']) self.produced_energy_forecast_kWh() self.offer_update.update_offer(self)
def __init__( self, avg_power_W, hrs_per_day=None, hrs_of_day=None, fit_to_limit=True, energy_rate_increase_per_update=1, update_interval=duration( minutes=ConstSettings.GeneralSettings.DEFAULT_UPDATE_INTERVAL), initial_buying_rate: Union[ float, dict, str] = ConstSettings.LoadSettings.INITIAL_BUYING_RATE, final_buying_rate: Union[ float, dict, str] = ConstSettings.LoadSettings.FINAL_BUYING_RATE, balancing_energy_ratio: tuple = ( ConstSettings.BalancingSettings.OFFER_DEMAND_RATIO, ConstSettings.BalancingSettings.OFFER_SUPPLY_RATIO), use_market_maker_rate: bool = False): """ Constructor of LoadHoursStrategy :param avg_power_W: Power rating of load device :param hrs_per_day: Daily energy usage :param hrs_of_day: hours of day energy is needed :param fit_to_limit: if set to True, it will make a linear curve following following initial_buying_rate & final_buying_rate :param energy_rate_increase_per_update: Slope of Load bids change per update :param update_interval: Interval after which Load will update its offer :param initial_buying_rate: Starting point of load's preferred buying rate :param final_buying_rate: Ending point of load's preferred buying rate :param use_market_maker_rate: If set to True, Load would track its final buying rate as per utility's trading rate """ # If use_market_maker_rate is true, overwrite final_buying_rate to market maker rate if use_market_maker_rate: final_buying_rate = GlobalConfig.market_maker_rate if isinstance(update_interval, int): update_interval = duration(minutes=update_interval) BidEnabledStrategy.__init__(self) self.bid_update = \ UpdateFrequencyMixin(initial_rate=initial_buying_rate, final_rate=final_buying_rate, fit_to_limit=fit_to_limit, energy_rate_change_per_update=energy_rate_increase_per_update, update_interval=update_interval, rate_limit_object=min) try: validate_load_device(avg_power_W=avg_power_W, hrs_per_day=hrs_per_day, hrs_of_day=hrs_of_day) except D3ADeviceException as e: raise D3ADeviceException(str(e)) for time_slot in generate_market_slot_list(): rate_change = self.bid_update.energy_rate_change_per_update[ time_slot] try: validate_load_device( initial_buying_rate=self.bid_update. initial_rate[time_slot], final_buying_rate=self.bid_update.final_rate[time_slot], energy_rate_increase_per_update=rate_change) except D3ADeviceException as e: raise D3ADeviceException(str(e)) self.state = LoadState() self.avg_power_W = avg_power_W # consolidated_cycle is KWh energy consumed for the entire year self.daily_energy_required = None # Energy consumed during the day ideally should not exceed daily_energy_required self.energy_per_slot_Wh = None self.energy_requirement_Wh = {} # type: Dict[Time, float] self.hrs_per_day = {} # type: Dict[int, int] self.assign_hours_of_per_day(hrs_of_day, hrs_per_day) self.balancing_energy_ratio = BalancingRatio(*balancing_energy_ratio)
def validate_range_limit(initial_limit, value, final_limit, error_message): if not initial_limit <= value <= final_limit: raise D3ADeviceException(error_message)
def _validate_home_meter_consumption_rates(**kwargs): """Validate rates related to the consumption activity of the device.""" if kwargs.get("final_buying_rate") is not None: error_message = { "misconfiguration": [ "final_buying_rate should be in between " f"{HomeMeterSettings.FINAL_BUYING_RATE_LIMIT.min} & " f"{HomeMeterSettings.FINAL_BUYING_RATE_LIMIT.max}." ] } validate_range_limit(HomeMeterSettings.FINAL_BUYING_RATE_LIMIT.min, kwargs["final_buying_rate"], HomeMeterSettings.FINAL_BUYING_RATE_LIMIT.max, error_message) if kwargs.get("initial_buying_rate") is not None: error_message = { "misconfiguration": [ "initial_buying_rate should be in between " f"{HomeMeterSettings.INITIAL_BUYING_RATE_LIMIT.min} & " f"{HomeMeterSettings.INITIAL_BUYING_RATE_LIMIT.max}" ] } validate_range_limit( HomeMeterSettings.INITIAL_BUYING_RATE_LIMIT.min, kwargs["initial_buying_rate"], HomeMeterSettings.INITIAL_BUYING_RATE_LIMIT.max, error_message) if (kwargs.get("initial_buying_rate") is not None and kwargs.get("final_buying_rate") is not None and kwargs["initial_buying_rate"] > kwargs["final_buying_rate"]): raise D3ADeviceException({ "misconfiguration": [ "initial_buying_rate should be less than or equal to final_buying_rate/" "market_maker_rate. Please adapt the market_maker_rate of the configuration " "or the initial_buying_rate." ] }) if kwargs.get("energy_rate_increase_per_update") is not None: error_message = { "misconfiguration": [ "energy_rate_increase_per_update should be in between " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min} & " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max}." ] } validate_range_limit( GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min, kwargs["energy_rate_increase_per_update"], GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max, error_message) if (kwargs.get("fit_to_limit") is True and kwargs.get("energy_rate_increase_per_update") is not None): raise D3ADeviceException({ "misconfiguration": [ "fit_to_limit & energy_rate_increase_per_update can't be set together." ] })
def validate_storage_device(**kwargs): if "initial_soc" in kwargs and kwargs["initial_soc"] is not None: error_message = \ {"misconfiguration": [f"initial_soc should be in between " f"{StorageSettings.INITIAL_CHARGE_LIMIT.min} & " f"{StorageSettings.INITIAL_CHARGE_LIMIT.max}."]} validate_range_limit(StorageSettings.INITIAL_CHARGE_LIMIT.min, kwargs["initial_soc"], StorageSettings.INITIAL_CHARGE_LIMIT.max, error_message) if "min_allowed_soc" in kwargs and kwargs["min_allowed_soc"] is not None: error_message = \ {"misconfiguration": [f"min_allowed_soc should be in between " f"{StorageSettings.MIN_SOC_LIMIT.min} & " f"{StorageSettings.MIN_SOC_LIMIT.max}."]} validate_range_limit(StorageSettings.MIN_SOC_LIMIT.min, kwargs["min_allowed_soc"], StorageSettings.MIN_SOC_LIMIT.max, error_message) if ("initial_soc" in kwargs and kwargs["initial_soc"] is not None) and \ ("min_allowed_soc" in kwargs and kwargs["min_allowed_soc"] is not None) and \ (kwargs["initial_soc"] < kwargs["min_allowed_soc"]): raise D3ADeviceException({ "misconfiguration": [ f"initial_soc should be greater " f"than or equal to min_allowed_soc." ] }) if "battery_capacity_kWh" in kwargs and kwargs[ "battery_capacity_kWh"] is not None: error_message = \ {"misconfiguration": [f"battery_capacity_kWh should be in between " f"{StorageSettings.CAPACITY_LIMIT.min} & " f"{StorageSettings.CAPACITY_LIMIT.max}."]} validate_range_limit(StorageSettings.CAPACITY_LIMIT.min, kwargs["battery_capacity_kWh"], StorageSettings.CAPACITY_LIMIT.max, error_message) if "max_abs_battery_power_kW" in kwargs and kwargs[ "max_abs_battery_power_kW"] is not None: error_message = \ {"misconfiguration": [f"max_abs_battery_power_kW should be in between " f"{StorageSettings.MAX_ABS_POWER_RANGE.initial} & " f"{StorageSettings.MAX_ABS_POWER_RANGE.final}."]} validate_range_limit(StorageSettings.MAX_ABS_POWER_RANGE.initial, kwargs["max_abs_battery_power_kW"], StorageSettings.MAX_ABS_POWER_RANGE.final, error_message) if "initial_selling_rate" in kwargs and kwargs[ "initial_selling_rate"] is not None: error_message = \ {"misconfiguration": [f"initial_selling_rate should be in between " f"{StorageSettings.INITIAL_SELLING_RATE_LIMIT.min} & " f"{StorageSettings.INITIAL_SELLING_RATE_LIMIT.max}."]} validate_range_limit(StorageSettings.INITIAL_SELLING_RATE_LIMIT.min, kwargs["initial_selling_rate"], StorageSettings.INITIAL_SELLING_RATE_LIMIT.max, error_message) if "final_selling_rate" in kwargs and kwargs[ "final_selling_rate"] is not None: error_message = \ {"misconfiguration": [f"final_selling_rate should be in between " f"{StorageSettings.FINAL_SELLING_RATE_LIMIT.min} & " f"{StorageSettings.FINAL_SELLING_RATE_LIMIT.max}."]} validate_range_limit(StorageSettings.FINAL_SELLING_RATE_LIMIT.min, kwargs["final_selling_rate"], StorageSettings.FINAL_SELLING_RATE_LIMIT.max, error_message) if ("initial_selling_rate" in kwargs and kwargs["initial_selling_rate"] is not None) and \ ("final_selling_rate" in kwargs and kwargs["final_selling_rate"] is not None) and \ (kwargs["initial_selling_rate"] < kwargs["final_selling_rate"]): raise D3ADeviceException({ "misconfiguration": [ f"initial_selling_rate should be greater " f"than or equal to final_selling_rate." ] }) if "initial_buying_rate" in kwargs and kwargs[ "initial_buying_rate"] is not None: error_message = \ {"misconfiguration": [f"initial_buying_rate should be in between " f"{StorageSettings.INITIAL_BUYING_RATE_LIMIT.min} & " f"{StorageSettings.INITIAL_BUYING_RATE_LIMIT.max}."]} validate_range_limit(StorageSettings.INITIAL_BUYING_RATE_LIMIT.min, kwargs["initial_buying_rate"], StorageSettings.INITIAL_BUYING_RATE_LIMIT.max, error_message) if "final_buying_rate" in kwargs and kwargs[ "final_buying_rate"] is not None: error_message = { "misconfiguration": [ f"final_buying_rate should be in between " f"{StorageSettings.FINAL_BUYING_RATE_LIMIT.min} & " f"{StorageSettings.FINAL_BUYING_RATE_LIMIT.max}." ] } validate_range_limit(StorageSettings.FINAL_BUYING_RATE_LIMIT.min, kwargs["final_buying_rate"], StorageSettings.FINAL_BUYING_RATE_LIMIT.max, error_message) if ("initial_buying_rate" in kwargs and kwargs["initial_buying_rate"] is not None) and \ ("final_buying_rate" in kwargs and kwargs["final_buying_rate"] is not None) and \ (kwargs["initial_buying_rate"] > kwargs["final_buying_rate"]): raise D3ADeviceException({ "misconfiguration": [ f"initial_buying_rate should be less " f"than or equal to final_buying_rate." ] }) if ("final_selling_rate" in kwargs and kwargs["final_selling_rate"] is not None) and \ ("final_buying_rate" in kwargs and kwargs["final_buying_rate"] is not None) and \ (kwargs["final_buying_rate"] > kwargs["final_selling_rate"]): raise D3ADeviceException({ "misconfiguration": [ f"final_buying_rate should be less " f"than or equal to final_selling_rate." ] }) if "energy_rate_increase_per_update" in kwargs and \ kwargs["energy_rate_increase_per_update"] is not None: error_message = \ {"misconfiguration": [f"energy_rate_increase_per_update should be in between " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min} & " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max}."]} validate_range_limit(GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min, kwargs["energy_rate_increase_per_update"], GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max, error_message) if "energy_rate_decrease_per_update" in kwargs and \ kwargs["energy_rate_decrease_per_update"] is not None: error_message = \ {"misconfiguration": [f"energy_rate_decrease_per_update should be in between " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min} & " f"{GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max}."]} validate_range_limit(GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.min, kwargs["energy_rate_decrease_per_update"], GeneralSettings.RATE_CHANGE_PER_UPDATE_LIMIT.max, error_message) if ("fit_to_limit" in kwargs and kwargs["fit_to_limit"] is True) and \ (("energy_rate_increase_per_update" in kwargs and kwargs["energy_rate_increase_per_update"] is not None) or ("energy_rate_decrease_per_update" in kwargs and kwargs["energy_rate_decrease_per_update"] is not None)): raise D3ADeviceException({ "misconfiguration": [ f"fit_to_limit & energy_rate_change_per_update " f"can't be set together." ] }) if key_in_dict_and_not_none(kwargs, "loss_function"): error_message = { "misconfiguration": [ f"loss_function should either be " f"{StorageSettings.LOSS_FUNCTION_LIMIT.min} or " f"{StorageSettings.LOSS_FUNCTION_LIMIT.max}." ] } validate_range_limit(StorageSettings.LOSS_FUNCTION_LIMIT.min, kwargs["loss_function"], StorageSettings.LOSS_FUNCTION_LIMIT.max, error_message) if key_in_dict_and_not_none(kwargs, "loss_per_hour"): if kwargs["loss_function"] == 1: error_message = { "misconfiguration": [ f"loss_per_hour should be in between " f"{StorageSettings.LOSS_PER_HOUR_RELATIVE_LIMIT.min} & " f"{StorageSettings.LOSS_PER_HOUR_RELATIVE_LIMIT.max}." ] } validate_range_limit( StorageSettings.LOSS_PER_HOUR_RELATIVE_LIMIT.min, kwargs["loss_per_hour"], StorageSettings.LOSS_PER_HOUR_RELATIVE_LIMIT.max, error_message) else: error_message = { "misconfiguration": [ f"loss_per_hour should be in between " f"{StorageSettings.LOSS_PER_HOUR_ABSOLUTE_LIMIT.min} & " f"{StorageSettings.LOSS_PER_HOUR_ABSOLUTE_LIMIT.max}." ] } validate_range_limit( StorageSettings.LOSS_PER_HOUR_ABSOLUTE_LIMIT.min, kwargs["loss_per_hour"], StorageSettings.LOSS_PER_HOUR_ABSOLUTE_LIMIT.max, error_message)
def validate_load_device_energy(**kwargs): if "avg_power_W" in kwargs and kwargs["avg_power_W"] is not None: error_message = { "misconfiguration": [ f"avg_power_W should be in between " f"{LoadSettings.AVG_POWER_LIMIT.min} & " f"{LoadSettings.AVG_POWER_LIMIT.max}." ] } validate_range_limit(LoadSettings.AVG_POWER_LIMIT.min, kwargs["avg_power_W"], LoadSettings.AVG_POWER_LIMIT.max, error_message) if (("avg_power_W" in kwargs and kwargs["avg_power_W"] is not None) or ("hrs_per_day" in kwargs and kwargs["hrs_per_day"] is not None) or ("hrs_of_day" in kwargs and kwargs["hrs_of_day"] is not None)) \ and ("daily_load_profile" in kwargs and kwargs["daily_load_profile"] is not None): raise D3ADeviceException({ "misconfiguration": [ f"daily_load_profile shouldn't be set with " f"avg_power_W, hrs_per_day & hrs_of_day." ] }) if "hrs_per_day" in kwargs and kwargs["hrs_per_day"] is not None: error_message = { "misconfiguration": [ f"hrs_per_day should be in between " f"{LoadSettings.HOURS_LIMIT.min} & " f"{LoadSettings.HOURS_LIMIT.max}." ] } validate_range_limit(LoadSettings.HOURS_LIMIT.min, kwargs["hrs_per_day"], LoadSettings.HOURS_LIMIT.max, error_message) if ("hrs_of_day" in kwargs and kwargs["hrs_of_day"] is not None) and \ any([not LoadSettings.HOURS_LIMIT.min <= h <= LoadSettings.HOURS_LIMIT.max for h in kwargs["hrs_of_day"]]): raise D3ADeviceException({ "misconfiguration": [ f"hrs_of_day should be less between " f"{LoadSettings.HOURS_LIMIT.min} & " f"{LoadSettings.HOURS_LIMIT.max}." ] }) if ("hrs_of_day" in kwargs and kwargs["hrs_of_day"] is not None) and \ ("hrs_per_day" in kwargs and kwargs["hrs_per_day"] is not None) and \ (len(kwargs["hrs_of_day"]) < kwargs["hrs_per_day"]): raise D3ADeviceException({ "misconfiguration": [ f"length of hrs_of_day list should be " f"greater than or equal hrs_per_day." ] }) if (("avg_power_W" in kwargs and kwargs["avg_power_W"] is not None) or ("hrs_per_day" in kwargs and kwargs["hrs_per_day"] is not None) or ("hrs_of_day" in kwargs and kwargs["hrs_of_day"] is not None)) and \ ("daily_load_profile" in kwargs and kwargs["daily_load_profile"] is not None): raise D3ADeviceException({ "misconfiguration": [ f"daily_load_profile and all or one [hrs_per_day, hrs_of_day, " f"avg_power_W] can't be set together." ] })