Skip to content

feat: parse power measurements in http-power and add a power read CLI command#790

Open
mmahut wants to merge 1 commit into
jumpstarter-dev:mainfrom
mmahut:mmahut/http-power-read
Open

feat: parse power measurements in http-power and add a power read CLI command#790
mmahut wants to merge 1 commit into
jumpstarter-dev:mainfrom
mmahut:mmahut/http-power-read

Conversation

@mmahut

@mmahut mmahut commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Previously the http-power driver's read() always returned dummy (0.0, 0.0) values.

read() now parses the JSON the read endpoint returns and pulls voltage/current out of it. By default it looks for top-level voltage/current keys, but you can point voltage_path/current_path at a dotted path (emeter.voltage, StatusSNS.ENERGY.Voltage, meters.0.voltage) for devices that nest them.

Tested against a real Shelly Plug S Gen3.

j-power

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cabdd831-8bee-43d0-af2f-822e23a85efc

📥 Commits

Reviewing files that changed from the base of the PR and between 24473f3 and d0897d8.

📒 Files selected for processing (5)
  • python/packages/jumpstarter-driver-http-power/README.md
  • python/packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/driver.py
  • python/packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/driver_test.py
  • python/packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py
  • python/packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py

📝 Walkthrough

Walkthrough

HTTP Power driver's dummy read() implementation is replaced with real JSON parsing using configurable dotted-path fields, proper error handling for missing config/invalid JSON/non-numeric values, and a new CLI read subcommand that streams formatted power measurements.

Changes

HTTP Power JSON Parsing and CLI Integration

Layer / File(s) Summary
HTTP Power config and JSON path utility
python/packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/driver.py
JSON import added. _json_path() utility traverses nested dicts/lists using dotted notation. HttpEndpointConfig extended with optional voltage_path and current_path fields to specify where voltage/current values are located in JSON responses.
HTTP Power read() parsing and extraction
python/packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/driver.py
HttpPower.read() now performs HTTP request, parses response as JSON, extracts voltage/current via configured paths, and yields PowerReading with parsed floats. Raises ValueError for missing power_read config, invalid JSON, missing configured paths, or non-numeric values. _extract_reading() static method centralizes path traversal and float coercion.
HTTP Power read() unit and integration tests
python/packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/driver_test.py
Existing test updated to validate parsed values from mock JSON instead of dummy zeros. New focused unit tests cover nested path parsing, missing-field defaulting, missing-path errors, non-numeric-index errors, invalid JSON, and missing endpoint configuration. Includes pytest import and _power() test helper.
HTTP Power README documentation
python/packages/jumpstarter-driver-http-power/README.md
Added Shelly Smart Plug Gen1 and Gen2/Gen3 configuration sections. Config parameters table documents voltage_path and current_path for dotted-path JSON extraction. "Reading measurements" section describes JSON parsing behavior, missing-field defaulting to 0.0, and configured-path error handling, replacing prior note claiming parsing was not implemented.
Power client read subcommand and tests
python/packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py, python/packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py
PowerClient CLI extended with read subcommand that streams power measurements and prints voltage, current, and apparent power for each reading. Tests verify read() method yields expected values and CLI invocation produces correctly formatted output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • jumpstarter-dev/jumpstarter#526: Extends the HTTP power driver implementation by replacing dummy HttpPower.read() behavior with real JSON/dotted-path parsing and updating tests and configuration fields.

Suggested labels

backport release-0.6

Suggested reviewers

  • kirkbrauer
  • NickCao
  • bennyz

Poem

🐰 A driver once slept, returning zeros in jest,
Now JSON paths wake it to parse with its best,
Volt and current dance through the dotted-path flight,
The CLI brings them to echo so bright! 📊✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: implementing real power measurement parsing in the http-power driver and adding a new CLI command for reading power values.
Description check ✅ Passed The description clearly explains the motivation (dummy values were being returned) and the solution (real JSON parsing with configurable paths), providing concrete examples of supported dotted paths and real-world testing context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@raballew raballew self-requested a review June 16, 2026 15:46
url: "http://192.168.1.65/cm?cmnd=Status%2010" # Tasmota
voltage_path: "StatusSNS.ENERGY.Voltage"
current_path: "StatusSNS.ENERGY.Current"
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide the examples for the shelly? I have one and would love to test it :)

@base.command()
def read():
"""Read power measurements"""
for reading in self.read():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the CLI we should probably perform a single read. Otherwise this will remain in a loop reading powers without any throttling.

Another option is to provide a number of readings, and the interval between them, may be default to 1s ?

@mangelajo mangelajo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a couple of comments but looks great :) thank you so much!

try:
return float(value)
except (TypeError, ValueError):
raise ValueError(f"value at {key!r} is not numeric: {value!r}") from None

@raballew raballew Jun 16, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message includes {value!r}, which dumps the full Python repr of whatever sits at the targeted path. Can a device response contain sensitive fields that should not leak into logs or client-visible error messages? If so consider including only the type name instead:

raise ValueError(f"value at {key!r} is not numeric (got {type(value).__name__})") from None

from jumpstarter.driver import Driver, export


def _json_path(data, path: str):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annotations missing:

def _json_path(data: Any, path: str) -> Any:
def _extract_reading(data: Any, path: Optional[str], default_key: str) -> float:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants