Reverse power flows, unified battery charging port#462
Conversation
There was a problem hiding this comment.
Pull request overview
Adds opt-in bidirectional (reverse) power-flow modeling to the voltage-port/link infrastructure, then refactors battery/charger-related parts and examples to use it while extending the expression/proto toolchain to support the required array operations.
Changes:
- Extend
VoltageSource/VoltageSink/VoltageLinkwithreverse_*voltage/current parameters and ERC rules (eg, unique reverse voltage source per link). - Refactor LiPo connector, MCP73831 charger, and PMOS reverse-protection blocks (and examples) to use the unified power port instead of a dedicated charging pseudo-port (with deprecation shims).
- Add proto + compiler support for array element equality (Range only) and boolean-array NOT, bumping the proto version and updating/adding tests.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| proto/edgir/expr.proto | Adds BinarySetExpr.EQ opcode for pointwise equality. |
| examples/test_protected_charger.py | Updates charger chaining to use unified bidirectional power port. |
| examples/test_pcbbot.py | Updates charger chaining to use unified bidirectional power port. |
| edg/parts/PowerConditioning.py | Refactors PMOS charger reverse-protection block to new reverse-flow params; adds deprecated alias accessors. |
| edg/parts/Connectors.py | Refactors LipoConnector to remove dedicated chg port and use reverse sink capability on pwr. |
| edg/parts/BatteryCharger_Mcp73831.py | Models charger battery pin as a reverse-capable VoltageSink (reverse source). |
| edg/hdl_server/main.py | Bumps EDG proto version. |
| edg/electronics_model/test_voltage_link.py | Replaces metadata test with compiler-level unit tests including reverse-flow cases. |
| edg/electronics_model/init.py | Exports dummy devices from electronics_model for unit testing. |
| edg/electronics_model/VoltagePorts.py | Implements reverse voltage/current propagation + ERC checks; updates bridges to include reverse params. |
| edg/electronics_model/VoltageDummyDevice.py | Adds voltage dummy devices in electronics_model (with reverse params). |
| edg/electronics_model/PassivePort.py | Extends passive voltage adapters to include reverse params. |
| edg/electronics_model/GroundDummyDevice.py | Adds ground dummy device in electronics_model. |
| edg/electronics_model/DummyDevice.py | Adds base dummy-device type under electronics_model. |
| edg/edgir/expr_pb2.pyi | Regenerated typing stubs for new proto opcode. |
| edg/edgir/expr_pb2.py | Regenerated python proto bindings for new opcode. |
| edg/core/Binding.py | Adds bindings for boolean-array NOT and array EQ (BinarySetExpr.EQ). |
| edg/core/ArrayExpr.py | Adds ArrayBoolExpr.__invert__ and ArrayRangeExpr.elts_equals(). |
| edg/abstract_parts/init.py | Removes export of DummyDevice from abstract parts. |
| edg/abstract_parts/DummyDevices.py | Removes local voltage/ground dummy implementations (now provided via electronics_model). |
| edg/abstract_parts/Categories.py | Removes DummyDevice definition from abstract parts categories. |
| compiler/src/test/scala/edg/compiler/ExprEvaluateTest.scala | Adds evaluation tests for unary-set negate on bool arrays and BinarySet EQ. |
| compiler/src/main/scala/edg/compiler/ExprToString.scala | Adds stringification for BinarySetExpr.EQ. |
| compiler/src/main/scala/edg/compiler/ExprEvaluate.scala | Implements evaluation for BinarySet EQ and boolean-array negate. |
| compiler/src/main/scala/edg/compiler/Compiler.scala | Bumps expected proto version. |
| compiler/src/main/scala/edg/ExprBuilder.scala | Adds Literal.RangeEmpty() helper for tests/builders. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
edg/electronics_model/DummyDevice.py
Outdated
| @@ -0,0 +1,8 @@ | |||
| from ..electronics_model import abstract_block, InternalBlock | |||
There was a problem hiding this comment.
This import introduces a circular dependency: edg.electronics_model.init imports DummyDevice, but DummyDevice imports from ..electronics_model (the package init). Importing electronics_model will recurse and can fail with partially initialized symbols. Import abstract_block / InternalBlock directly from edg.core (or the defining module) instead of from the electronics_model package aggregator.
| from ..electronics_model import abstract_block, InternalBlock | |
| from ..core import abstract_block, InternalBlock |
edg/parts/PowerConditioning.py
Outdated
| # taking the max of the current for the both direction. 0 lower bound | ||
| batt_current = self.pwr_out.link().current_drawn.hull(self.chg_out.link().current_drawn).hull((0, 0)) | ||
| batt_current = self.pwr_out.link().current_drawn.hull(self.pwr_in.link().reverse_current_drawn) |
There was a problem hiding this comment.
The comment says the battery current range is clamped to a 0 lower bound, but the updated expression no longer hulls with (0, 0). Either reintroduce the explicit 0 lower-bound clamp or update the comment to match the new behavior (and ensure negative ranges can’t occur if that’s a requirement).
Resolves #330.
Adds a reverse voltage direction for VoltageSource/Sink. Only at most one reverse voltage source per connection (and combined with the unique forward VoltageSource requirement, means at most one bidirectional power path). Adds unit tests.
Refactors the LiPo connector, Mcp73831 battery charger IC, and reverse-capable PMOS reverse voltage protector to use this new infrastructure and eliminates the dedicated charging pseudo-port.
This refactors the voltage DummyDevices to the electronics_model to support unit tests. The other ones should eventually be migrated
To check for reverse source uniqueness, this adds some code infrastructure: