From 834aebe7194fa9d849e2b2d6f419788ab85aa1a1 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 26 Nov 2025 11:38:09 +0100 Subject: [PATCH 1/2] metadata for optional --- packages/control/ocpp.py | 6 +- packages/control/ocpp_test.py | 4 +- packages/control/optional.py | 7 +-- packages/control/optional_data.py | 78 ++++++++++++++++--------- packages/helpermodules/update_config.py | 2 - 5 files changed, 55 insertions(+), 42 deletions(-) diff --git a/packages/control/ocpp.py b/packages/control/ocpp.py index 104d1c2dde..5eeac407de 100644 --- a/packages/control/ocpp.py +++ b/packages/control/ocpp.py @@ -27,8 +27,8 @@ def _process_call(self: OptionalProtocol, fault_state: FaultState, func: Callable) -> Optional[websockets.WebSocketClientProtocol]: async def make_call() -> websockets.WebSocketClientProtocol: - async with websockets.connect(self.data.ocpp.url+chargebox_id, - subprotocols=[self.data.ocpp.version]) as ws: + async with websockets.connect(self.data.ocpp.config.url+chargebox_id, + subprotocols=[self.data.ocpp.config.version]) as ws: try: cp = OcppChargepoint(chargebox_id, ws, 2) await cp.call(func) @@ -37,7 +37,7 @@ async def make_call() -> websockets.WebSocketClientProtocol: pass return ws try: - if self.data.ocpp.active and chargebox_id: + if self.data.ocpp.config.active and chargebox_id: return asyncio.run(make_call()) except websockets.exceptions.InvalidStatusCode: fault_state.warning(f"Chargebox ID {chargebox_id} konnte nicht im OCPP-Backend gefunden werden oder " diff --git a/packages/control/ocpp_test.py b/packages/control/ocpp_test.py index 5dae1c50ff..cd2e93d8f6 100644 --- a/packages/control/ocpp_test.py +++ b/packages/control/ocpp_test.py @@ -13,8 +13,8 @@ @pytest.fixture() def mock_data() -> None: data.data_init(Mock()) - data.data.optional_data.data.ocpp.active = True - data.data.optional_data.data.ocpp.url = "ws://localhost:9000/" + data.data.optional_data.data.ocpp.config.active = True + data.data.optional_data.data.ocpp.config.url = "ws://localhost:9000/" def test_start_transaction(mock_data, monkeypatch): diff --git a/packages/control/optional.py b/packages/control/optional.py index 753dfcc0f9..f07e3e6c84 100644 --- a/packages/control/optional.py +++ b/packages/control/optional.py @@ -162,13 +162,10 @@ def remove(price_data: Dict) -> Dict: if self.data.electricity_pricing.configured: ep = self.data.electricity_pricing ep.get.prices = remove(ep.get.prices) - Pub().pub("openWB/set/optional/ep/get/prices", ep.get.prices) if self._flexible_tariff_module: ep.flexible_tariff.get.prices = remove(ep.flexible_tariff.get.prices) - Pub().pub("openWB/set/optional/ep/flexible_tariff/get/prices", ep.flexible_tariff.get.prices) if self._grid_fee_module: ep.grid_fee.get.prices = remove(ep.grid_fee.get.prices) - Pub().pub("openWB/set/optional/ep/grid_fee/get/prices", ep.grid_fee.get.prices) def __get_current_timeslot_start(self) -> int: timestamp = self.__get_first_entry()[0] @@ -264,7 +261,6 @@ def get_last_entry_time_stamp() -> str: minutes=random.randint(1, 7) * -5 ) self.data.electricity_pricing.get.next_query_time = next_query_time.timestamp() - Pub().pub("openWB/set/optional/ep/get/next_query_time", self.data.electricity_pricing.get.next_query_time) return True if is_tomorrow(get_last_entry_time_stamp()): if timecheck.create_timestamp() > self.data.electricity_pricing.get.next_query_time: @@ -281,7 +277,7 @@ def get_last_entry_time_stamp() -> str: def ocpp_transfer_meter_values(self): try: - if self.data.ocpp.active: + if self.data.ocpp.config.active: thread_handler(Thread(target=self._transfer_meter_values, args=(), name="OCPP Client")) except Exception as e: log.exception("Fehler im OCPP-Optional-Modul: %s", e) @@ -296,7 +292,6 @@ def _transfer_meter_values(self): cp.chargepoint_module.config.type, cp.data.get.serial_number) self.data.ocpp.boot_notification_sent = True - Pub().pub("openWB/set/optional/ocpp/boot_notification_sent", True) if cp.data.set.ocpp_transaction_id is not None: self.send_heart_beat(cp.data.config.ocpp_chargebox_id, cp.chargepoint_module.fault_state) self.transfer_values(cp.data.config.ocpp_chargebox_id, diff --git a/packages/control/optional_data.py b/packages/control/optional_data.py index 0f96ff0ec0..0d17a15056 100644 --- a/packages/control/optional_data.py +++ b/packages/control/optional_data.py @@ -8,18 +8,31 @@ @dataclass class PricingGet: - fault_state: int = 0 - fault_str: str = NO_ERROR + fault_state: int = field(default=0) + fault_str: str = field(default=NO_ERROR) prices: Dict = field(default_factory=empty_dict_factory) -def get_factory() -> PricingGet: - return PricingGet() +def create_pricing_get_with_topics(topic_prefix: str) -> PricingGet: + """Factory function to create PricingGet with custom topic prefix""" + pricing_get = PricingGet() + pricing_get.__dataclass_fields__['fault_state'].metadata = {"topic": f"{topic_prefix}/get/fault_state"} + pricing_get.__dataclass_fields__['fault_str'].metadata = {"topic": f"{topic_prefix}/get/fault_str"} + pricing_get.__dataclass_fields__['prices'].metadata = {"topic": f"{topic_prefix}/get/prices"} + return pricing_get + + +def flexible_tariff_get_factory() -> PricingGet: + return create_pricing_get_with_topics("ep/flexible_tariff") + + +def grid_fee_get_factory() -> PricingGet: + return create_pricing_get_with_topics("ep/grid_fee") @dataclass class FlexibleTariff: - get: PricingGet = field(default_factory=get_factory) + get: PricingGet = field(default_factory=flexible_tariff_get_factory) def get_flexible_tariff_factory() -> FlexibleTariff: @@ -28,7 +41,7 @@ def get_flexible_tariff_factory() -> FlexibleTariff: @dataclass class GridFee: - get: PricingGet = field(default_factory=get_factory) + get: PricingGet = field(default_factory=grid_fee_get_factory) def get_grid_fee_factory() -> GridFee: @@ -37,8 +50,8 @@ def get_grid_fee_factory() -> GridFee: @dataclass class ElectricityPricingGet: - next_query_time: Optional[float] = None - prices: Dict = field(default_factory=empty_dict_factory) + next_query_time: Optional[float] = field(default=None, metadata={"topic": "ep/next_query_time"}) + prices: Dict = field(default_factory=empty_dict_factory, metadata={"topic": "ep/prices"}) def electricity_pricing_get_factory() -> ElectricityPricingGet: @@ -47,7 +60,7 @@ def electricity_pricing_get_factory() -> ElectricityPricingGet: @dataclass class ElectricityPricing: - configured: bool = False + configured: bool = field(default=False, metadata={"topic": "ep/configured"}) flexible_tariff: FlexibleTariff = field(default_factory=get_flexible_tariff_factory) grid_fee: GridFee = field(default_factory=get_grid_fee_factory) get: ElectricityPricingGet = field(default_factory=electricity_pricing_get_factory) @@ -57,14 +70,22 @@ def ep_factory() -> ElectricityPricing: return ElectricityPricing() +def cards_display_theme_factory() -> CardsDisplayTheme: + return CardsDisplayTheme() + + @dataclass class InternalDisplay: - active: bool = False - on_if_plugged_in: bool = True - pin_active: bool = False - pin_code: str = "0000" - standby: int = 60 - theme: CardsDisplayTheme = CardsDisplayTheme() + active: bool = field(default=False, metadata={"topic": "int_display/active"}) + detected: bool = field(default=False, metadata={"topic": "int_display/detected"}) + on_if_plugged_in: bool = field(default=True, metadata={"topic": "int_display/on_if_plugged_in"}) + only_local_charge_points: bool = field(default=False, metadata={"topic": "int_display/only_local_charge_points"}) + pin_active: bool = field(default=False, metadata={"topic": "int_display/pin_active"}) + pin_code: str = field(default="0000", metadata={"topic": "int_display/pin_code"}) + rotation: int = field(default=0, metadata={"topic": "int_display/rotation"}) + standby: int = field(default=60, metadata={"topic": "int_display/standby"}) + theme: CardsDisplayTheme = field(default_factory=cards_display_theme_factory, + metadata={"topic": "int_display/theme"}) def int_display_factory() -> InternalDisplay: @@ -72,29 +93,29 @@ def int_display_factory() -> InternalDisplay: @dataclass -class Led: - active: bool = False +class Rfid: + active: bool = field(default=False, metadata={"topic": "rfid/active"}) -def led_factory() -> Led: - return Led() +def rfid_factory() -> Rfid: + return Rfid() @dataclass -class Rfid: +class OcppConfig: active: bool = False + _url: Optional[str] = None + version: str = "ocpp1.6" -def rfid_factory() -> Rfid: - return Rfid() +def ocpp_config_factory() -> OcppConfig: + return OcppConfig() @dataclass class Ocpp: - active: bool = False - boot_notification_sent: bool = False - _url: Optional[str] = None - version: str = "ocpp1.6" + config: OcppConfig = field(default_factory=ocpp_config_factory) + boot_notification_sent: bool = field(default=False, metadata={"topic": "ocpp/boot_notification_sent"}) @property def url(self) -> Optional[str]: @@ -116,10 +137,9 @@ def ocpp_factory() -> Ocpp: class OptionalData: electricity_pricing: ElectricityPricing = field(default_factory=ep_factory) int_display: InternalDisplay = field(default_factory=int_display_factory) - led: Led = field(default_factory=led_factory) rfid: Rfid = field(default_factory=rfid_factory) - dc_charging: bool = False - ocpp: Ocpp = field(default_factory=ocpp_factory) + dc_charging: bool = field(default=False, metadata={"topic": "dc_charging"}) + ocpp: Ocpp = field(default_factory=ocpp_factory, metadata={"topic": "ocpp/config"}) class OptionalProtocol(Protocol): diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 8650124c05..0b35c2ebdc 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -325,7 +325,6 @@ class UpdateConfig: "^openWB/optional/int_display/rotation$", "^openWB/optional/int_display/theme$", "^openWB/optional/int_display/only_local_charge_points", - "^openWB/optional/led/active$", "^openWB/optional/monitoring/config$", "^openWB/optional/rfid/active$", "^openWB/optional/ocpp/config$", @@ -584,7 +583,6 @@ class UpdateConfig: ("openWB/optional/int_display/rotation", 0), ("openWB/optional/int_display/theme", dataclass_utils.asdict(CardsDisplayTheme())), ("openWB/optional/int_display/only_local_charge_points", False), - ("openWB/optional/led/active", False), ("openWB/optional/monitoring/config", NO_MODULE), ("openWB/optional/ocpp/config", dataclass_utils.asdict(Ocpp())), ("openWB/optional/rfid/active", False), From 4e5e188b39af9a9d044efb3897b94ae13cd88c64 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 26 Nov 2025 11:38:50 +0100 Subject: [PATCH 2/2] ammend --- packages/helpermodules/changed_values_handler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/helpermodules/changed_values_handler.py b/packages/helpermodules/changed_values_handler.py index 3239bc520c..073223e514 100644 --- a/packages/helpermodules/changed_values_handler.py +++ b/packages/helpermodules/changed_values_handler.py @@ -83,6 +83,8 @@ def pub_changed_values(self): data.data.cp_all_data.data.get) self._update_value("openWB/set/counter/", self.prev_data.counter_all_data.data, data.data.counter_all_data.data) + self._update_value("openWB/set/optional/", self.prev_data.optional_data.data, + data.data.optional_data.data) for key, value in data.data.cp_data.items(): self._update_value(f"openWB/set/chargepoint/{value.num}/", self.prev_data.cp_data[key].data, value.data) for key, value in data.data.bat_data.items():