|
| 1 | +# License: MIT |
| 2 | +# Copyright © 2022 Frequenz Energy-as-a-Service GmbH |
| 3 | + |
| 4 | +"""Defines the components that can be used in a microgrid.""" |
| 5 | +from __future__ import annotations |
| 6 | + |
| 7 | +from enum import Enum |
| 8 | + |
| 9 | +# pylint: disable=no-name-in-module |
| 10 | +from frequenz.api.common.v1.microgrid.components.components_pb2 import ( |
| 11 | + ComponentCategory as PBComponentCategory, |
| 12 | +) |
| 13 | +from frequenz.api.common.v1.microgrid.components.components_pb2 import ( |
| 14 | + ComponentErrorCode as PBComponentErrorCode, |
| 15 | +) |
| 16 | +from frequenz.api.common.v1.microgrid.components.components_pb2 import ( |
| 17 | + ComponentStateCode as PBComponentStateCode, |
| 18 | +) |
| 19 | + |
| 20 | +# pylint: enable=no-name-in-module |
| 21 | + |
| 22 | + |
| 23 | +class ComponentCategory(Enum): |
| 24 | + """Possible types of microgrid component.""" |
| 25 | + |
| 26 | + UNSPECIFIED = PBComponentCategory.COMPONENT_CATEGORY_UNSPECIFIED |
| 27 | + """An unknown component category. |
| 28 | +
|
| 29 | + Useful for error handling, and marking unknown components in |
| 30 | + a list of components with otherwise known categories. |
| 31 | + """ |
| 32 | + |
| 33 | + GRID = PBComponentCategory.COMPONENT_CATEGORY_GRID |
| 34 | + """The point where the local microgrid is connected to the grid.""" |
| 35 | + |
| 36 | + METER = PBComponentCategory.COMPONENT_CATEGORY_METER |
| 37 | + """A meter, for measuring electrical metrics, e.g., current, voltage, etc.""" |
| 38 | + |
| 39 | + INVERTER = PBComponentCategory.COMPONENT_CATEGORY_INVERTER |
| 40 | + """An electricity generator, with batteries or solar energy.""" |
| 41 | + |
| 42 | + BATTERY = PBComponentCategory.COMPONENT_CATEGORY_BATTERY |
| 43 | + """A storage system for electrical energy, used by inverters.""" |
| 44 | + |
| 45 | + EV_CHARGER = PBComponentCategory.COMPONENT_CATEGORY_EV_CHARGER |
| 46 | + """A station for charging electrical vehicles.""" |
| 47 | + |
| 48 | + CHP = PBComponentCategory.COMPONENT_CATEGORY_CHP |
| 49 | + """A heat and power combustion plant (CHP stands for combined heat and power).""" |
| 50 | + |
| 51 | + @classmethod |
| 52 | + def from_proto( |
| 53 | + cls, component_category: PBComponentCategory.ValueType |
| 54 | + ) -> ComponentCategory: |
| 55 | + """Convert a protobuf ComponentCategory message to ComponentCategory enum. |
| 56 | +
|
| 57 | + Args: |
| 58 | + component_category: protobuf enum to convert |
| 59 | +
|
| 60 | + Returns: |
| 61 | + Enum value corresponding to the protobuf message. |
| 62 | + """ |
| 63 | + if not any(t.value == component_category for t in ComponentCategory): |
| 64 | + return ComponentCategory.UNSPECIFIED |
| 65 | + return cls(component_category) |
| 66 | + |
| 67 | + def to_proto(self) -> PBComponentCategory.ValueType: |
| 68 | + """Convert a ComponentCategory enum to protobuf ComponentCategory message. |
| 69 | +
|
| 70 | + Returns: |
| 71 | + Enum value corresponding to the protobuf message. |
| 72 | + """ |
| 73 | + return self.value |
| 74 | + |
| 75 | + |
| 76 | +class ComponentStateCode(Enum): |
| 77 | + """All possible states of a microgrid component.""" |
| 78 | + |
| 79 | + UNSPECIFIED = PBComponentStateCode.COMPONENT_STATE_CODE_UNSPECIFIED |
| 80 | + """Default value when the component state is not explicitly set.""" |
| 81 | + |
| 82 | + UNKNOWN = PBComponentStateCode.COMPONENT_STATE_CODE_UNKNOWN |
| 83 | + """State when the component is in an unknown or undefined condition. |
| 84 | +
|
| 85 | + This is used when the sender is unable to classify the component into any |
| 86 | + other state. |
| 87 | + """ |
| 88 | + SWITCHING_OFF = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_OFF |
| 89 | + """State when the component is in the process of switching off.""" |
| 90 | + |
| 91 | + OFF = PBComponentStateCode.COMPONENT_STATE_CODE_OFF |
| 92 | + """State when the component has successfully switched off.""" |
| 93 | + |
| 94 | + SWITCHING_ON = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_ON |
| 95 | + """State when the component is in the process of switching on from an off state.""" |
| 96 | + |
| 97 | + STANDBY = PBComponentStateCode.COMPONENT_STATE_CODE_STANDBY |
| 98 | + """State when the component is in standby mode, and not immediately ready for operation.""" |
| 99 | + |
| 100 | + READY = PBComponentStateCode.COMPONENT_STATE_CODE_READY |
| 101 | + """State when the component is fully operational and ready for use.""" |
| 102 | + |
| 103 | + CHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_CHARGING |
| 104 | + """State when the component is actively consuming energy.""" |
| 105 | + |
| 106 | + DISCHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_DISCHARGING |
| 107 | + """State when the component is actively producing or releasing energy.""" |
| 108 | + |
| 109 | + ERROR = PBComponentStateCode.COMPONENT_STATE_CODE_ERROR |
| 110 | + """State when the component is in an error state and may need attention.""" |
| 111 | + |
| 112 | + EV_CHARGING_CABLE_UNPLUGGED = ( |
| 113 | + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_UNPLUGGED |
| 114 | + ) |
| 115 | + """The Electric Vehicle (EV) charging cable is unplugged from the charging station.""" |
| 116 | + |
| 117 | + EV_CHARGING_CABLE_PLUGGED_AT_STATION = ( |
| 118 | + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_STATION |
| 119 | + ) |
| 120 | + """The EV charging cable is plugged into the charging station.""" |
| 121 | + |
| 122 | + EV_CHARGING_CABLE_PLUGGED_AT_EV = ( |
| 123 | + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_EV |
| 124 | + ) |
| 125 | + """The EV charging cable is plugged into the vehicle.""" |
| 126 | + |
| 127 | + EV_CHARGING_CABLE_LOCKED_AT_STATION = ( |
| 128 | + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_STATION |
| 129 | + ) |
| 130 | + """The EV charging cable is locked at the charging station end, indicating |
| 131 | + readiness for charging.""" |
| 132 | + |
| 133 | + EV_CHARGING_CABLE_LOCKED_AT_EV = ( |
| 134 | + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_EV |
| 135 | + ) |
| 136 | + """The EV charging cable is locked at the vehicle end, indicating that charging is active.""" |
| 137 | + |
| 138 | + RELAY_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_OPEN |
| 139 | + """The relay is in an open state, meaning no current can flow through.""" |
| 140 | + |
| 141 | + RELAY_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_CLOSED |
| 142 | + """The relay is in a closed state, allowing current to flow.""" |
| 143 | + |
| 144 | + PRECHARGER_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_OPEN |
| 145 | + """The precharger circuit is open, meaning it's not currently active.""" |
| 146 | + |
| 147 | + PRECHARGER_PRECHARGING = ( |
| 148 | + PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_PRECHARGING |
| 149 | + ) |
| 150 | + """The precharger is in a precharging state, preparing the main circuit for activation.""" |
| 151 | + |
| 152 | + PRECHARGER_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_CLOSED |
| 153 | + """The precharger circuit is closed, allowing full current to flow to the main circuit.""" |
| 154 | + |
| 155 | + @classmethod |
| 156 | + def from_proto( |
| 157 | + cls, component_state: PBComponentStateCode.ValueType |
| 158 | + ) -> ComponentStateCode: |
| 159 | + """Convert a protobuf ComponentStateCode message to ComponentStateCode enum. |
| 160 | +
|
| 161 | + Args: |
| 162 | + component_state: protobuf enum to convert |
| 163 | +
|
| 164 | + Returns: |
| 165 | + Enum value corresponding to the protobuf message. |
| 166 | + """ |
| 167 | + if not any(c.value == component_state for c in ComponentStateCode): |
| 168 | + return ComponentStateCode.UNSPECIFIED |
| 169 | + return cls(component_state) |
| 170 | + |
| 171 | + def to_proto(self) -> PBComponentStateCode.ValueType: |
| 172 | + """Convert a ComponentStateCode enum to protobuf ComponentStateCode message. |
| 173 | +
|
| 174 | + Returns: |
| 175 | + Enum value corresponding to the protobuf message. |
| 176 | + """ |
| 177 | + return self.value |
| 178 | + |
| 179 | + |
| 180 | +class ComponentErrorCode(Enum): |
| 181 | + """All possible errors that can occur across all microgrid component categories.""" |
| 182 | + |
| 183 | + UNSPECIFIED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNSPECIFIED |
| 184 | + """Default value. No specific error is specified.""" |
| 185 | + |
| 186 | + UNKNOWN = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNKNOWN |
| 187 | + """The component is reporting an unknown or an undefined error, and the sender |
| 188 | + cannot parse the component error to any of the variants below.""" |
| 189 | + |
| 190 | + SWITCH_ON_FAULT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SWITCH_ON_FAULT |
| 191 | + """Error indicating that the component could not be switched on.""" |
| 192 | + |
| 193 | + UNDERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE |
| 194 | + """Error indicating that the component is operating under the minimum rated |
| 195 | + voltage.""" |
| 196 | + |
| 197 | + OVERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERVOLTAGE |
| 198 | + """Error indicating that the component is operating over the maximum rated |
| 199 | + voltage.""" |
| 200 | + |
| 201 | + OVERCURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT |
| 202 | + """Error indicating that the component is drawing more current than the |
| 203 | + maximum rated value.""" |
| 204 | + |
| 205 | + OVERCURRENT_CHARGING = ( |
| 206 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_CHARGING |
| 207 | + ) |
| 208 | + """Error indicating that the component's consumption current is over the |
| 209 | + maximum rated value during charging.""" |
| 210 | + |
| 211 | + OVERCURRENT_DISCHARGING = ( |
| 212 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_DISCHARGING |
| 213 | + ) |
| 214 | + """Error indicating that the component's production current is over the |
| 215 | + maximum rated value during discharging.""" |
| 216 | + |
| 217 | + OVERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERTEMPERATURE |
| 218 | + """Error indicating that the component is operating over the maximum rated |
| 219 | + temperature.""" |
| 220 | + |
| 221 | + UNDERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERTEMPERATURE |
| 222 | + """Error indicating that the component is operating under the minimum rated |
| 223 | + temperature.""" |
| 224 | + |
| 225 | + HIGH_HUMIDITY = PBComponentErrorCode.COMPONENT_ERROR_CODE_HIGH_HUMIDITY |
| 226 | + """Error indicating that the component is exposed to high humidity levels over |
| 227 | + the maximum rated value.""" |
| 228 | + |
| 229 | + FUSE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_FUSE_ERROR |
| 230 | + """Error indicating that the component's fuse has blown.""" |
| 231 | + |
| 232 | + PRECHARGE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PRECHARGE_ERROR |
| 233 | + """Error indicating that the component's precharge unit has failed.""" |
| 234 | + |
| 235 | + PLAUSIBILITY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PLAUSIBILITY_ERROR |
| 236 | + """Error indicating plausibility issues within the system involving this |
| 237 | + component.""" |
| 238 | + |
| 239 | + UNDERVOLTAGE_SHUTDOWN = ( |
| 240 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE_SHUTDOWN |
| 241 | + ) |
| 242 | + """Error indicating system shutdown due to undervoltage involving this |
| 243 | + component.""" |
| 244 | + |
| 245 | + EV_UNEXPECTED_PILOT_FAILURE = ( |
| 246 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_UNEXPECTED_PILOT_FAILURE |
| 247 | + ) |
| 248 | + """Error indicating unexpected pilot failure in an electric vehicle (EV) |
| 249 | + component.""" |
| 250 | + |
| 251 | + FAULT_CURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_FAULT_CURRENT |
| 252 | + """Error indicating fault current detected in the component.""" |
| 253 | + |
| 254 | + SHORT_CIRCUIT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SHORT_CIRCUIT |
| 255 | + """Error indicating a short circuit detected in the component.""" |
| 256 | + |
| 257 | + CONFIG_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_CONFIG_ERROR |
| 258 | + """Error indicating a configuration error related to the component.""" |
| 259 | + |
| 260 | + ILLEGAL_COMPONENT_STATE_CODE_REQUESTED = ( |
| 261 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_ILLEGAL_COMPONENT_STATE_CODE_REQUESTED |
| 262 | + ) |
| 263 | + """Error indicating an illegal state requested for the component.""" |
| 264 | + |
| 265 | + HARDWARE_INACCESSIBLE = ( |
| 266 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_HARDWARE_INACCESSIBLE |
| 267 | + ) |
| 268 | + """Error indicating that the hardware of the component is inaccessible.""" |
| 269 | + |
| 270 | + INTERNAL = PBComponentErrorCode.COMPONENT_ERROR_CODE_INTERNAL |
| 271 | + """Error indicating an internal error within the component.""" |
| 272 | + |
| 273 | + UNAUTHORIZED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNAUTHORIZED |
| 274 | + """Error indicating that the component is unauthorized to perform the |
| 275 | + last requested action.""" |
| 276 | + |
| 277 | + EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION = ( |
| 278 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION |
| 279 | + ) |
| 280 | + """Error indicating electric vehicle (EV) cable was abruptly unplugged from |
| 281 | + the charging station.""" |
| 282 | + |
| 283 | + EV_CHARGING_CABLE_UNPLUGGED_FROM_EV = ( |
| 284 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_EV |
| 285 | + ) |
| 286 | + """Error indicating electric vehicle (EV) cable was abruptly unplugged from |
| 287 | + the vehicle.""" |
| 288 | + |
| 289 | + EV_CHARGING_CABLE_LOCK_FAILED = ( |
| 290 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_LOCK_FAILED |
| 291 | + ) |
| 292 | + """Error indicating electric vehicle (EV) cable lock failure.""" |
| 293 | + |
| 294 | + EV_CHARGING_CABLE_INVALID = ( |
| 295 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_INVALID |
| 296 | + ) |
| 297 | + """Error indicating an invalid electric vehicle (EV) cable.""" |
| 298 | + |
| 299 | + EV_CONSUMER_INCOMPATIBLE = ( |
| 300 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CONSUMER_INCOMPATIBLE |
| 301 | + ) |
| 302 | + """Error indicating an incompatible electric vehicle (EV) plug.""" |
| 303 | + |
| 304 | + BATTERY_IMBALANCE = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_IMBALANCE |
| 305 | + """Error indicating a battery system imbalance.""" |
| 306 | + |
| 307 | + BATTERY_LOW_SOH = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_LOW_SOH |
| 308 | + """Error indicating a low state of health (SOH) detected in the battery.""" |
| 309 | + |
| 310 | + BATTERY_BLOCK_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_BLOCK_ERROR |
| 311 | + """Error indicating a battery block error.""" |
| 312 | + |
| 313 | + BATTERY_CONTROLLER_ERROR = ( |
| 314 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CONTROLLER_ERROR |
| 315 | + ) |
| 316 | + """Error indicating a battery controller error.""" |
| 317 | + |
| 318 | + BATTERY_RELAY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_RELAY_ERROR |
| 319 | + """Error indicating a battery relay error.""" |
| 320 | + |
| 321 | + BATTERY_CALIBRATION_NEEDED = ( |
| 322 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CALIBRATION_NEEDED |
| 323 | + ) |
| 324 | + """Error indicating that battery calibration is needed.""" |
| 325 | + |
| 326 | + RELAY_CYCLE_LIMIT_REACHED = ( |
| 327 | + PBComponentErrorCode.COMPONENT_ERROR_CODE_RELAY_CYCLE_LIMIT_REACHED |
| 328 | + ) |
| 329 | + """Error indicating that the relays have been cycled for the maximum number of |
| 330 | + times.""" |
| 331 | + |
| 332 | + @classmethod |
| 333 | + def from_proto( |
| 334 | + cls, component_error_code: PBComponentErrorCode.ValueType |
| 335 | + ) -> ComponentErrorCode: |
| 336 | + """Convert a protobuf ComponentErrorCode message to ComponentErrorCode enum. |
| 337 | +
|
| 338 | + Args: |
| 339 | + component_error_code: protobuf enum to convert |
| 340 | +
|
| 341 | + Returns: |
| 342 | + Enum value corresponding to the protobuf message. |
| 343 | + """ |
| 344 | + if not any(c.value == component_error_code for c in ComponentErrorCode): |
| 345 | + return ComponentErrorCode.UNSPECIFIED |
| 346 | + return cls(component_error_code) |
| 347 | + |
| 348 | + def to_proto(self) -> PBComponentErrorCode.ValueType: |
| 349 | + """Convert a ComponentErrorCode enum to protobuf ComponentErrorCode message. |
| 350 | +
|
| 351 | + Returns: |
| 352 | + Enum value corresponding to the protobuf message. |
| 353 | + """ |
| 354 | + return self.value |
0 commit comments