Esempio n. 1
0
    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."]
        })
Esempio n. 3
0
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."]})
Esempio n. 4
0
    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()
Esempio n. 5
0
 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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
 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)
Esempio n. 9
0
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)
Esempio n. 10
0
 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
Esempio n. 11
0
    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)
Esempio n. 13
0
    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 {}
Esempio n. 14
0
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
Esempio n. 15
0
    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()
Esempio n. 16
0
    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})
Esempio n. 18
0
 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'])
Esempio n. 19
0
 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")
Esempio n. 20
0
 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)
Esempio n. 21
0
 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)
Esempio n. 22
0
 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)
Esempio n. 23
0
 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()
Esempio n. 24
0
 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)
Esempio n. 26
0
 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']
Esempio n. 27
0
 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()