Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion docs/samples/sample_consumer/sample_consumer/consumer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from enum import IntEnum
import logging
from modules.common.abstract_consumer import CurrentValues
from modules.common.abstract_device import DeviceDescriptor
from modules.common.component_state import ConsumerState
from modules.common.configurable_consumer import ConfigurableConsumer
Expand Down Expand Up @@ -52,23 +53,32 @@ def update() -> ConsumerState:
temperatures=[resp[Register.TEMP0]/10, resp[Register.TEMP1]/10, resp[Register.TEMP2]/10]
)

# ConsumerUsage.SUSPENDABLE_TUNABLE
def set_limit(power_limit: float) -> None:
nonlocal client
client.write_registers(1000, power_limit, unit=config.configuration.modbus_id)

# ODER

# ConsumerUsage.SUSPENDABLE_ONOFF
# ConsumerUsage.CONTINUOUS
def switch_on() -> None:
nonlocal client
client.write_registers(1000, 1, unit=config.configuration.modbus_id)

def switch_off() -> None:
nonlocal client
client.write_registers(1000, 0, unit=config.configuration.modbus_id)

# ODER
# ConsumerUsage.SELF_CONTROLLED
def send_values(values: CurrentValues) -> None:
client.write_registers(1000, values.evu_power, unit=config.configuration.modbus_id)

return ConfigurableConsumer(consumer_config=config,
initializer=initializer,
error_handler=error_handler,
update=update,
send_values=send_values,
set_power_limit=set_limit,
switch_on=switch_on,
switch_off=switch_off)
Expand Down
3 changes: 2 additions & 1 deletion packages/control/consumer/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Callable, Dict, List, Optional, Tuple

from control import data
from control.consumer.usage import NOT_CONTROLLED
from control.algorithm.utils import get_medium_charging_current
from control.chargemode import Chargemode
from control.chargepoint.chargepoint_state import CHARGING_STATES, ChargepointState
Expand Down Expand Up @@ -42,7 +43,7 @@ def setup_values_at_start(self):
def update(self):
try:
self.setup_values_at_start()
if self.data.usage.type == ConsumerUsage.METER_ONLY:
if self.data.usage.type in NOT_CONTROLLED:
return
else:
if self.data.get.voltages is None:
Expand Down
22 changes: 8 additions & 14 deletions packages/control/consumer/consumer_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ class ResetChargemode:
chargemode: Chargemode = Chargemode.INSTANT_CHARGING


@dataclass
class Log:
on_time: float = 0


@dataclass
class Usage:
chargemode: Chargemode = Chargemode.INSTANT_CHARGING
Expand Down Expand Up @@ -93,18 +88,17 @@ class Get:
@dataclass
class Set:
current: float = field(default=0, metadata={"topic": "set/current"})
loadmanagement_available: bool = False
loadmanagement_available: bool = field(default=False)
phases_to_use: int = field(default=1, metadata={"topic": "set/phases_to_use"})
plug_time: Optional[float] = field(default=None, metadata={"topic": "set/plug_time"})
required_power: float = 0
current_prev: float = 0
state_str_prev: str = ""
target_current: float = 0
charge_state_prev: bool = False
log: Log = field(default_factory=lambda: Log())
required_power: float = field(default=0)
current_prev: float = field(default=0)
state_str_prev: str = field(default="")
target_current: float = field(default=0)
charge_state_prev: bool = field(default=False)
on_time: float = field(default=0, metadata={"topic": "set/on_time"})
power: Optional[float] = None
switch_interval_elapsed: bool = False
power: Optional[float] = field(default=None)
switch_interval_elapsed: bool = field(default=False)
timestamp_last_current_set: float = field(default=0, metadata={"topic": "set/timestamp_last_current_set"})
wait_for_start_state: WaitForStartStates = field(
default=WaitForStartStates.WAIT_FOR_DEVICE_START, metadata={"topic": "set/wait_for_start_state"})
Expand Down
4 changes: 4 additions & 0 deletions packages/control/consumer/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

class ConsumerUsage(Enum):
METER_ONLY = "meter_only"
SELF_CONTROLLED = "self_controlled"
SUSPENDABLE_TUNABLE = "suspendable_tunable"
SUSPENDABLE_ONOFF = "suspendable_onoff"
CONTINUOUS = "continuous"


NOT_CONTROLLED = (ConsumerUsage.METER_ONLY, ConsumerUsage.SELF_CONTROLLED)
20 changes: 17 additions & 3 deletions packages/control/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from helpermodules.phase_handling import voltages_mean
from helpermodules.pub import Pub
from helpermodules.utils._thread_handler import joined_thread_handler
from modules.common.abstract_consumer import CurrentValues
from modules.common.abstract_io import AbstractIoDevice
from modules.common.configurable_device import set_power_limit_wrapper
from modules.common.fault_state_level import FaultStateLevel
Expand Down Expand Up @@ -187,6 +188,19 @@ def _start_consumer(self, consumer: Consumer) -> Thread:
return Thread(
target=consumer.module.switch_on if consumer.data.set.current > 0 else consumer.module.switch_off,
name=f"set current consumer{consumer.num}")
return Thread(target=consumer.module.set_power_limit,
args=(consumer.data.set.power,),
name=f"set current consumer{consumer.num}")
elif consumer.data.usage.type == ConsumerUsage.SELF_CONTROLLED:
current_values = CurrentValues(
bat_power=data.data.bat_all_data.data.get.power,
bat_soc=data.data.bat_all_data.data.get.soc,
cp_power=data.data.cp_all_data.data.get.power,
evu_power=data.data.counter_all_data.get_evu_counter().data.get.power,
home_consumption=data.data.counter_all_data.data.set.home_consumption,
pv_power=data.data.pv_all_data.data.get.power
)
return Thread(target=consumer.module.send_values,
args=(current_values,),
name=f"set current consumer{consumer.num}")
Comment on lines +200 to +202
else:
return Thread(target=consumer.module.set_power_limit,
args=(consumer.data.set.power,),
name=f"set current consumer{consumer.num}")
10 changes: 7 additions & 3 deletions packages/helpermodules/setdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,9 @@ def process_mqtt_topic(self, msg: mqtt.MQTTMessage):
elif "openWB/set/mqtt/consumer/" in msg.topic:
if re.search("openWB/set/mqtt/consumer/[0-9]+/set/switch", msg.topic) is not None:
self._validate_value(msg, bool)
elif re.search("openWB/set/mqtt/consumer/[0-9]+/set/power", msg.topic) is not None:
elif re.search("openWB/set/mqtt/consumer/[0-9]+/set/"
+ "(power|bat_power|bat_soc|cp_power|evu_power|home_consumption|pv_power)",
msg.topic) is not None:
self._validate_value(msg, float)
else:
self.process_consumer_topic(msg)
Expand Down Expand Up @@ -1270,9 +1272,11 @@ def process_consumer_topic(self, msg):
re.search("consumer/[0-9]+/get/daily_imported$", msg.topic) is not None or
re.search("consumer/[0-9]+/get/timestamp_last_current_set$", msg.topic) is not None):
self._validate_value(msg, float, [(0, float("inf"))])
elif re.search("consumer/[0-9]+/get/fault_state$", msg.topic) is not None:
elif (re.search("consumer/[0-9]+/get/fault_state$", msg.topic) is not None or
re.search("consumer/get/fault_state$", msg.topic) is not None):
self._validate_value(msg, int, [(0, 2)])
elif (re.search("consumer/[0-9]+/get/fault_str$", msg.topic) is not None or
elif (re.search("consumer/get/fault_str$", msg.topic) is not None or
re.search("consumer/[0-9]+/get/fault_str$", msg.topic) is not None or
re.search("consumer/[0-9]+/get/state_str$", msg.topic) is not None or
re.search("consumer/[0-9]+/set/wait_for_start_state$", msg.topic) is not None):
self._validate_value(msg, str)
Expand Down
11 changes: 11 additions & 0 deletions packages/modules/common/abstract_consumer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from dataclasses import dataclass


@dataclass
class CurrentValues:
bat_power: float = 0
bat_soc: float = 0
cp_power: float = 0
evu_power: float = 0
home_consumption: float = 0
pv_power: float = 0
7 changes: 7 additions & 0 deletions packages/modules/common/configurable_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from helpermodules import timecheck
from helpermodules.pub import Pub
from modules.common.abstract_consumer import CurrentValues
from modules.common.abstract_device import AbstractCounter
from modules.common.component_context import SingleComponentUpdateContext
from modules.common.component_state import ConsumerState
Expand All @@ -24,13 +25,15 @@ def __init__(self,
initializer: Optional[Callable] = lambda: None,
error_handler: Optional[Callable] = lambda: None,
update: Optional[Callable[[], ConsumerState]] = lambda: None,
send_values: Optional[Callable[[CurrentValues], None]] = lambda: None,
set_power_limit: Optional[Callable] = lambda: None,
switch_on: Optional[Callable] = lambda: None,
switch_off: Optional[Callable] = lambda: None,) -> None:
self.config = consumer_config
self.module_initializer = initializer
self.module_error_handler = error_handler
self.module_updater = update
self.module_send_values = send_values
self.module_set_power_limit = set_power_limit
self.module_switch_on = switch_on
self.module_switch_off = switch_off
Expand Down Expand Up @@ -88,6 +91,10 @@ def switch_off(self) -> None:
with SingleComponentUpdateContext(self.fault_state):
self.module_switch_off()

def send_values(self, values: CurrentValues) -> None:
with SingleComponentUpdateContext(self.fault_state):
self.module_send_values(values)


def dependency_injection_devices_components(component: AbstractCounter):
component.sim_counter.component_type = ComponentType.CONSUMER.value
Expand Down
1 change: 1 addition & 0 deletions packages/modules/consumers/generic/mqtt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def __init__(self,
configuration: MqttConfiguration = None,
usage: Tuple[ConsumerUsage, ...] = (ConsumerUsage.METER_ONLY,
ConsumerUsage.CONTINUOUS,
ConsumerUsage.SELF_CONTROLLED,
ConsumerUsage.SUSPENDABLE_ONOFF,
ConsumerUsage.SUSPENDABLE_TUNABLE),
**kwargs) -> None:
Expand Down
11 changes: 11 additions & 0 deletions packages/modules/consumers/generic/mqtt/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from helpermodules.pub import Pub
from helpermodules.utils._get_default import get_default
from helpermodules.utils.topic_parser import decode_payload
from modules.common.abstract_consumer import CurrentValues
from modules.common.abstract_device import DeviceDescriptor
from modules.common.component_state import ConsumerState
from modules.common.configurable_consumer import ConfigurableConsumer
Expand Down Expand Up @@ -50,8 +51,18 @@ def switch_on() -> None:

def switch_off() -> None:
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/switch", False)

def send_values(values: CurrentValues) -> None:
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/bat_power", values.bat_power)
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/bat_soc", values.bat_soc)
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/cp_power", values.cp_power)
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/evu_power", values.evu_power)
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/home_consumption", values.home_consumption)
Pub().pub(f"openWB/set/mqtt/consumer/{config.id}/set/pv_power", values.pv_power)

return ConfigurableConsumer(consumer_config=config,
update=update,
send_values=send_values,
set_power_limit=set_power_limit,
switch_on=switch_on,
switch_off=switch_off)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const statusColor = computed(() => {
});

const meterOnly = computed(
() => mqttStore.consumerUsageType(props.consumerId) === 'meter_only',
() => mqttStore.consumerUsageType(props.consumerId) === 'meter_only' || mqttStore.consumerUsageType(props.consumerId) === 'self_controlled',
);

const consumerColor = computed(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const consumerUsageType = computed(() =>

/** Meter-only consumers cannot be controlled, so hide the mode controls. */
const showModeControls = computed(
() => consumerUsageType.value !== 'meter_only',
() => consumerUsageType.value !== 'meter_only' && consumerUsageType.value !== 'self_controlled',
);
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export interface ConsumerModule {
}
export type ConsumerUsageType =
| 'meter_only'
| 'self_controlled'
| 'suspendable_tunable'
| 'suspendable_onoff'
| 'continuous';
Expand Down
Loading