def area_reconfigure_event(self, **kwargs): if self.strategy is not None: self.strategy.area_reconfigure_event(**kwargs) return if key_in_dict_and_not_none(kwargs, 'transfer_fee_const') or \ key_in_dict_and_not_none(kwargs, 'grid_fee_percentage'): transfer_fee_const = kwargs["transfer_fee_const"] \ if key_in_dict_and_not_none(kwargs, 'transfer_fee_const') else None grid_fee_percentage = kwargs["grid_fee_percentage"] \ if key_in_dict_and_not_none(kwargs, 'grid_fee_percentage') else None validate_area(grid_fee_percentage=grid_fee_percentage, grid_fee_constant=transfer_fee_const) self._set_grid_fees(transfer_fee_const, grid_fee_percentage) if key_in_dict_and_not_none(kwargs, 'baseline_peak_energy_import_kWh'): self.baseline_peak_energy_import_kWh = kwargs[ 'baseline_peak_energy_import_kWh'] validate_area(baseline_peak_energy_import_kWh=self. baseline_peak_energy_import_kWh) if key_in_dict_and_not_none(kwargs, 'baseline_peak_energy_export_kWh'): self.baseline_peak_energy_export_kWh = kwargs[ 'baseline_peak_energy_export_kWh'] validate_area(baseline_peak_energy_export_kWh=self. baseline_peak_energy_export_kWh) if key_in_dict_and_not_none(kwargs, 'import_capacity_kVA') or \ key_in_dict_and_not_none(kwargs, 'export_capacity_kVA'): import_capacity_kVA = kwargs["import_capacity_kVA"] \ if key_in_dict_and_not_none(kwargs, 'import_capacity_kVA') else None export_capacity_kVA = kwargs["export_capacity_kVA"] \ if key_in_dict_and_not_none(kwargs, 'export_capacity_kVA') else None validate_area(import_capacity_kVA=import_capacity_kVA, export_capacity_kVA=export_capacity_kVA) self._convert_area_throughput_kva_to_kwh(import_capacity_kVA, export_capacity_kVA)
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_area(**kwargs): is_percentage_fee = key_in_dict_and_not_none(kwargs, "grid_fee_percentage") is_constant_fee = key_in_dict_and_not_none(kwargs, "grid_fee_constant") if is_percentage_fee and is_constant_fee: raise D3AException("Cannot set both percentage and constant grid fees on the same area.") if is_percentage_fee: error_message = {"misconfiguration": [f"grid_fee_percentage should be in between " f"{AreaSettings.GRID_FEE_PERCENTAGE_LIMIT.min} & " f"{AreaSettings.GRID_FEE_PERCENTAGE_LIMIT.max}."]} validate_range_limit(AreaSettings.GRID_FEE_PERCENTAGE_LIMIT.min, kwargs["grid_fee_percentage"], AreaSettings.GRID_FEE_PERCENTAGE_LIMIT.max, error_message) elif is_constant_fee: error_message = {"misconfiguration": [f"grid_fee_constant should be in between " f"{CONSTANT_FEE_LIMIT.min} & " f"{CONSTANT_FEE_LIMIT.max}."]} validate_range_limit(CONSTANT_FEE_LIMIT.min, kwargs["grid_fee_constant"], CONSTANT_FEE_LIMIT.max, error_message) if key_in_dict_and_not_none_and_negative(kwargs, "baseline_peak_energy_import_kWh"): raise D3AException({"misconfiguration": [f"baseline_peak_energy_import_kWh must be a " f"positive value."]}) if key_in_dict_and_not_none_and_negative(kwargs, "baseline_peak_energy_export_kWh"): raise D3AException({"misconfiguration": [f"baseline_peak_energy_export_kWh must be a " f"positive value."]}) if key_in_dict_and_not_none_and_negative(kwargs, "import_capacity_kVA"): raise D3AException( {"misconfiguration": [f"import_capacity_kVA must be a positive value."]}) if key_in_dict_and_not_none_and_negative(kwargs, "export_capacity_kVA"): raise D3AException({"misconfiguration": [f"export_capacity_kVA must be a " f"positive value."]})
def area_reconfigure_event(self, validate=True, **kwargs): self._area_reconfigure_prices(validate, **kwargs) validate_pv_device_energy(**kwargs) if key_in_dict_and_not_none(kwargs, 'panel_count'): self.panel_count = kwargs['panel_count'] if key_in_dict_and_not_none(kwargs, 'max_panel_power_W'): self.max_panel_power_W = kwargs['max_panel_power_W'] self.produced_energy_forecast_kWh()
def to_json_string(self) -> str: # __dict__ instead of asdict to not recursively deserialize objects trade_dict = deepcopy(self.__dict__) trade_dict["offer_bid"] = trade_dict["offer_bid"].to_json_string() if key_in_dict_and_not_none(trade_dict, "residual"): trade_dict["residual"] = trade_dict["residual"].to_json_string() if key_in_dict_and_not_none(trade_dict, "offer_bid_trade_info"): trade_dict["offer_bid_trade_info"] = ( trade_dict["offer_bid_trade_info"].to_json_string()) return json.dumps(trade_dict, default=my_converter)
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" self._area_reconfigure_prices(**kwargs) self.offer_update.update_and_populate_price_settings(self.area) if key_in_dict_and_not_none(kwargs, 'panel_count'): self.panel_count = kwargs['panel_count'] if key_in_dict_and_not_none(kwargs, 'max_panel_power_W'): self.max_panel_power_W = kwargs['max_panel_power_W'] self.set_produced_energy_forecast_kWh_future_markets(reconfigure=True)
def area_reconfigure_event(self, **kwargs): if key_in_dict_and_not_none(kwargs, 'hrs_per_day') or \ key_in_dict_and_not_none(kwargs, 'hrs_of_day'): self.assign_hours_of_per_day(kwargs['hrs_of_day'], kwargs['hrs_per_day']) self.hrs_per_day = {day: self._initial_hrs_per_day for day in range(self.area.config.sim_duration.days + 1)} if key_in_dict_and_not_none(kwargs, 'avg_power_W'): self.avg_power_W = kwargs['avg_power_W'] self.assign_energy_requirement(kwargs['avg_power_W']) self._area_reconfigure_prices(**kwargs)
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" if key_in_dict_and_not_none(kwargs, 'hrs_per_day') or \ key_in_dict_and_not_none(kwargs, 'hrs_of_day'): self.assign_hours_of_per_day(kwargs['hrs_of_day'], kwargs['hrs_per_day']) self.add_entry_in_hrs_per_day(overwrite=True) if key_in_dict_and_not_none(kwargs, 'avg_power_W'): self.avg_power_W = kwargs['avg_power_W'] self._update_energy_requirement_future_markets() self._area_reconfigure_prices(**kwargs) self.bid_update.update_and_populate_price_settings(self.area)
def trade_from_json_string(trade_string, current_time=None) -> Trade: trade_dict = json.loads(trade_string) trade_dict["offer_bid"] = offer_or_bid_from_json_string( trade_dict["offer_bid"], current_time) if key_in_dict_and_not_none(trade_dict, "residual"): trade_dict["residual"] = offer_or_bid_from_json_string( trade_dict["residual"], current_time) trade_dict["time"] = parse(trade_dict["time"]) if key_in_dict_and_not_none(trade_dict, "offer_bid_trade_info"): trade_dict["offer_bid_trade_info"] = (trade_bid_info_from_json_string( trade_dict["offer_bid_trade_info"])) return Trade(**trade_dict)
def _area_reconfigure_prices(self, **kwargs): if key_in_dict_and_not_none(kwargs, 'initial_selling_rate'): self.offer_update.initial_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['initial_selling_rate']) if key_in_dict_and_not_none(kwargs, 'final_selling_rate'): self.offer_update.final_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['final_selling_rate']) if key_in_dict_and_not_none(kwargs, 'initial_buying_rate'): self.bid_update.initial_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['initial_buying_rate']) if key_in_dict_and_not_none(kwargs, 'final_buying_rate'): self.bid_update.final_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['final_buying_rate']) if key_in_dict_and_not_none(kwargs, 'energy_rate_decrease_per_update'): self.offer_update.energy_rate_change_per_update = \ read_arbitrary_profile(InputProfileTypes.IDENTITY, kwargs['energy_rate_decrease_per_update']) if key_in_dict_and_not_none(kwargs, 'energy_rate_increase_per_update'): self.bid_update.energy_rate_change_per_update = \ read_arbitrary_profile(InputProfileTypes.IDENTITY, kwargs['energy_rate_increase_per_update']) if key_in_dict_and_not_none(kwargs, 'fit_to_limit'): self.bid_update.fit_to_limit = kwargs['fit_to_limit'] self.offer_update.fit_to_limit = kwargs['fit_to_limit'] if key_in_dict_and_not_none(kwargs, 'update_interval'): if isinstance(kwargs['update_interval'], int): update_interval = duration(minutes=kwargs['update_interval']) else: update_interval = kwargs['update_interval'] self.bid_update.update_interval = update_interval self.offer_update.update_interval = update_interval
def sanitize_parameters(cls, data_dict, current_time): if (key_in_dict_and_not_none(data_dict, "offer_or_id") and isinstance(data_dict["offer_or_id"], str)): data_dict["offer_or_id"] = ( offer_or_bid_from_json_string(data_dict["offer_or_id"], current_time)) if key_in_dict_and_not_none(data_dict, "offer") and isinstance(data_dict["offer"], str): data_dict["offer"] = ( offer_or_bid_from_json_string(data_dict["offer"], current_time)) if key_in_dict_and_not_none(data_dict, "bid") and isinstance(data_dict["bid"], str): data_dict["bid"] = ( offer_or_bid_from_json_string(data_dict["bid"])) if key_in_dict_and_not_none(data_dict, "trade") and isinstance(data_dict["trade"], str): data_dict["trade"] = ( trade_from_json_string(data_dict["trade"], current_time)) return data_dict
def _update_results(self, area_dict, core_stats, current_market_slot): if not key_in_dict_and_not_none(area_dict, 'children'): return self._calculate_market_summary_for_area(area_dict, core_stats, current_market_slot) for child in area_dict['children']: self._update_results(child, core_stats, current_market_slot)
def _swap_children_names_to_uuids(cls, area_dict, area_uuid, area_results): if not key_in_dict_and_not_none(area_dict, "children"): return {} if key_in_dict_and_not_none(area_dict, "name") and \ key_in_dict_and_not_none(area_dict, "uuid") and \ area_uuid == area_dict["uuid"]: child_name_uuid_mapping = { c["name"]: c["uuid"] for c in area_dict["children"] } return { child_name_uuid_mapping.get(k, k): v for k, v in area_results.items() } for child in area_dict["children"]: converted_result = cls._swap_children_names_to_uuids( child, area_uuid, area_results) if converted_result: return converted_result return {}
def area_from_dict(description, config): def optional(attr): return _instance_from_dict( description[attr]) if attr in description else None try: if 'type' in description: return _leaf_from_dict(description, config) # Area is a Leaf name = description['name'] uuid = description.get('uuid', None) external_connection_available = description.get( 'allow_external_connection', False) baseline_peak_energy_import_kWh = description.get( 'baseline_peak_energy_import_kWh', None) baseline_peak_energy_export_kWh = description.get( 'baseline_peak_energy_export_kWh', None) import_capacity_kVA = description.get('import_capacity_kVA', None) export_capacity_kVA = description.get('export_capacity_kVA', None) if key_in_dict_and_not_none(description, 'children'): children = [ area_from_dict(child, config) for child in description['children'] ] else: children = None grid_fee_percentage = description.get('grid_fee_percentage', None) grid_fee_constant = description.get('grid_fee_constant', None) area = Area( name, children, uuid, optional('strategy'), config, optional('budget_keeper'), grid_fee_percentage=grid_fee_percentage, grid_fee_constant=grid_fee_constant, external_connection_available=external_connection_available and config.external_connection_enabled, throughput=ThroughputParameters( baseline_peak_energy_import_kWh=baseline_peak_energy_import_kWh, baseline_peak_energy_export_kWh=baseline_peak_energy_export_kWh, import_capacity_kVA=import_capacity_kVA, export_capacity_kVA=export_capacity_kVA)) if "display_type" in description: area.display_type = description["display_type"] return area except (json.JSONDecodeError, KeyError, TypeError, ValueError) as error: raise ValueError("Input is not a valid area description (%s)" % str(error)) from error
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" if self.strategy is not None: self.strategy.area_reconfigure_event(**kwargs) return True grid_fee_constant = ( kwargs["grid_fee_constant"] if key_in_dict_and_not_none(kwargs, "grid_fee_constant") else self.grid_fee_constant) grid_fee_percentage = ( kwargs["grid_fee_percentage"] if key_in_dict_and_not_none(kwargs, "grid_fee_percentage") else self.grid_fee_percentage) baseline_peak_energy_import_kWh = ( kwargs["baseline_peak_energy_import_kWh"] if key_in_dict_and_not_none( kwargs, "baseline_peak_energy_import_kWh") else self.throughput.baseline_peak_energy_import_kWh) baseline_peak_energy_export_kWh = ( kwargs["baseline_peak_energy_export_kWh"] if key_in_dict_and_not_none( kwargs, "baseline_peak_energy_export_kWh") else self.throughput.baseline_peak_energy_export_kWh) import_capacity_kVA = ( kwargs["import_capacity_kVA"] if key_in_dict_and_not_none(kwargs, "import_capacity_kVA") else self.throughput.import_capacity_kVA) export_capacity_kVA = ( kwargs["export_capacity_kVA"] if key_in_dict_and_not_none(kwargs, "export_capacity_kVA") else self.throughput.import_capacity_kVA) try: validate_area(grid_fee_constant=grid_fee_constant, grid_fee_percentage=grid_fee_percentage) throughput = ThroughputParameters( baseline_peak_energy_import_kWh=baseline_peak_energy_import_kWh, baseline_peak_energy_export_kWh=baseline_peak_energy_export_kWh, import_capacity_kVA=import_capacity_kVA, export_capacity_kVA=export_capacity_kVA ) except Exception as ex: log.error(ex) return self._set_grid_fees(grid_fee_constant, grid_fee_percentage) self.throughput = throughput self._update_descendants_strategy_prices()
def _area_reconfigure_prices(self, **kwargs): if key_in_dict_and_not_none(kwargs, 'initial_selling_rate'): initial_rate = read_arbitrary_profile( InputProfileTypes.IDENTITY, kwargs['initial_selling_rate']) else: initial_rate = self.offer_update.initial_rate_profile_buffer if key_in_dict_and_not_none(kwargs, 'final_selling_rate'): final_rate = read_arbitrary_profile(InputProfileTypes.IDENTITY, kwargs['final_selling_rate']) else: final_rate = self.offer_update.final_rate_profile_buffer if key_in_dict_and_not_none(kwargs, 'energy_rate_decrease_per_update'): energy_rate_change_per_update = \ read_arbitrary_profile(InputProfileTypes.IDENTITY, kwargs['energy_rate_decrease_per_update']) else: energy_rate_change_per_update = \ self.offer_update.energy_rate_change_per_update_profile_buffer if key_in_dict_and_not_none(kwargs, 'fit_to_limit'): fit_to_limit = kwargs['fit_to_limit'] else: fit_to_limit = self.offer_update.fit_to_limit if key_in_dict_and_not_none(kwargs, 'update_interval'): if isinstance(kwargs['update_interval'], int): update_interval = duration(minutes=kwargs['update_interval']) else: update_interval = kwargs['update_interval'] else: update_interval = self.offer_update.update_interval if key_in_dict_and_not_none(kwargs, 'use_market_maker_rate'): self.use_market_maker_rate = kwargs['use_market_maker_rate'] try: self._validate_rates(initial_rate, final_rate, energy_rate_change_per_update, fit_to_limit) except Exception as e: log.error( f"PVStrategy._area_reconfigure_prices failed. Exception: {e}. " f"Traceback: {traceback.format_exc()}") return self.offer_update.set_parameters( initial_rate_profile_buffer=initial_rate, final_rate_profile_buffer=final_rate, energy_rate_change_per_update_profile_buffer= energy_rate_change_per_update, fit_to_limit=fit_to_limit, update_interval=update_interval)
def _convert_output_format(price_energy, redis_output, core_stats): for node_uuid, trade_rates in price_energy.items(): if node_uuid not in redis_output: redis_output[node_uuid] = { "price-currency": "Euros", "load-unit": "kWh", "price-energy-day": [] } redis_output[node_uuid]["price-energy-day"] = [{ "time": timeslot, "min_price": round_floats_for_ui(min(trades) if len(trades) > 0 else 0), "max_price": round_floats_for_ui(max(trades) if len(trades) > 0 else 0), } for timeslot, trades in trade_rates.items()] area_core_stats = core_stats.get(node_uuid, {}) fee = area_core_stats['grid_fee_constant'] / 100 \ if key_in_dict_and_not_none(area_core_stats, 'grid_fee_constant') else None redis_output[node_uuid]["price-energy-day"][0].update( {"grid_fee_constant": fee})
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" self._area_reconfigure_prices(**kwargs) if key_in_dict_and_not_none(kwargs, 'daily_load_profile'): self._event_activate_energy(kwargs['daily_load_profile'])
def _get_transaction_id(payload): data = json.loads(payload["data"]) if key_in_dict_and_not_none(data, "transaction_id"): return data["transaction_id"] else: raise ValueError("transaction_id not in payload or None")
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" super().area_reconfigure_event(**kwargs) if key_in_dict_and_not_none(kwargs, 'power_profile'): self._power_profile_W = kwargs['power_profile'] self.set_produced_energy_forecast_kWh_future_markets(reconfigure=True)
def area_reconfigure_event(self, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" if key_in_dict_and_not_none(kwargs, 'cloud_coverage'): self.cloud_coverage = kwargs['cloud_coverage'] super().area_reconfigure_event(**kwargs)
def area_reconfigure_event(self, *args, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" if key_in_dict_and_not_none(kwargs, "allow_external_connection"): self._use_template_strategy = not kwargs[ "allow_external_connection"] super().area_reconfigure_event(*args, **kwargs)
def area_reconfigure_event(self, validate=True, **kwargs): super().area_reconfigure_event(validate=validate, **kwargs) if key_in_dict_and_not_none(kwargs, 'cloud_coverage'): self.cloud_coverage = kwargs['cloud_coverage'] self.read_config_event()
def area_reconfigure_event(self, **kwargs): self._area_reconfigure_prices(**kwargs) if key_in_dict_and_not_none(kwargs, 'daily_load_profile'): self._event_activate_energy(kwargs['daily_load_profile'])
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 area_reconfigure_event(self, *args, **kwargs): """Reconfigure the device properties at runtime using the provided arguments.""" super().area_reconfigure_event(*args, **kwargs) if key_in_dict_and_not_none(kwargs, 'grid_connected'): self._grid_connected = kwargs['grid_connected']
def area_reconfigure_event(self, validate=True, **kwargs): super().area_reconfigure_event(validate=validate, **kwargs) if key_in_dict_and_not_none(kwargs, 'power_profile'): self._power_profile_W = kwargs['power_profile'] self.read_config_event()