Skip to content

Add support for LinkPi SmartHUB power port#1729

Open
Kwiboo wants to merge 1 commit intolabgrid-project:masterfrom
Kwiboo:linkpismarthub
Open

Add support for LinkPi SmartHUB power port#1729
Kwiboo wants to merge 1 commit intolabgrid-project:masterfrom
Kwiboo:linkpismarthub

Conversation

@Kwiboo
Copy link
Copy Markdown
Contributor

@Kwiboo Kwiboo commented Sep 9, 2025

Description
LinkPi SmartHUB is a 12-port USB3.0 HUB utilizing four RTS5411 USB3.0 4-port HUB controllers, a FT232R USB UART IC and a STM32F103RB MCU for port power control. Maximum output power of each USB port is up to 15W.

Add a LinkPiSmartHUBPowerPort resource and a LinkPiSmartHUBPowerDriver with an accompanying linkpismarthub agent to support power on/off the ports of the LinkPi SmartHUB using a simple line-based protocol over a serial port.

Known commands:

  • onoff <port> <1|0> - switch port power on/off
  • state - get current power state of all ports
  • SetOWP <1|0> <1|0> ... - set the power-on state of all ports
  • GetOWP - get the power-on state of all ports

Responses are in JSON format, e.g.:

> onoff 5 1
< {"Cmd":"OnOffResp","SeqNum":1,"ret":0}
> state
< {"Cmd":"StateResp","SeqNum":2,"state":[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]}
> SetOWP 0 0 0 0 0 0 0 0 0 0 0 1
< {"Cmd":"SetOWPResp","SeqNum":3,"ret":0}
> GetOWP
< {"Cmd":"GetOWPResp","SeqNum":4,"owp":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]}

A version announcement is continuously sent every second:

< {"Cmd":"VerResp","ver":"SmartHUB_<ver>","uid":"<uid>"}

Please note that the port name printed on the hub does not match the internal port index used with the commands.

Links

Information on the LinkPi SmartHUB is hard to find, following links mention it:

Checklist

  • Documentation for the feature
  • Tests for the feature
  • The arguments and description in doc/configuration.rst have been updated
  • PR has been tested

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 9, 2025

Codecov Report

❌ Patch coverage is 86.86869% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.0%. Comparing base (3912486) to head (b1bdb6c).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
labgrid/remote/exporter.py 0.0% 7 Missing ⚠️
labgrid/remote/client.py 0.0% 3 Missing ⚠️
labgrid/driver/powerdriver.py 97.4% 1 Missing ⚠️
labgrid/resource/suggest.py 0.0% 1 Missing ⚠️
labgrid/resource/udev.py 93.3% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master   #1729     +/-   ##
========================================
+ Coverage    45.8%   46.0%   +0.2%     
========================================
  Files         182     183      +1     
  Lines       14718   14816     +98     
========================================
+ Hits         6743    6829     +86     
- Misses       7975    7987     +12     
Flag Coverage Δ
3.10 46.0% <86.8%> (+0.2%) ⬆️
3.11 46.0% <86.8%> (+0.2%) ⬆️
3.12 46.0% <86.8%> (+0.2%) ⬆️
3.13 46.0% <86.8%> (+0.2%) ⬆️
3.14 46.0% <86.8%> (+0.2%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Kwiboo Kwiboo force-pushed the linkpismarthub branch 3 times, most recently from b741e89 to d956ef3 Compare September 13, 2025 11:29
@Kwiboo Kwiboo force-pushed the linkpismarthub branch 2 times, most recently from 3549390 to b5bc7df Compare October 5, 2025 08:58
@Kwiboo Kwiboo force-pushed the linkpismarthub branch 2 times, most recently from c782167 to 2f70e4c Compare November 28, 2025 16:17
@Kwiboo Kwiboo force-pushed the linkpismarthub branch 2 times, most recently from 3953541 to 931b1fd Compare February 6, 2026 17:47
self.path = path

def _command(self, command):
with serial.Serial(self.path, 115200, timeout=2) as s:
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.

How do we handle the case when two users want to switch different ports simultenously? Is the serial.open() already going to fail, what does the error message look like?

Copy link
Copy Markdown
Contributor Author

@Kwiboo Kwiboo Mar 13, 2026

Choose a reason for hiding this comment

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

I was able to trigger an error reading power status for two different ports after a few tries of parallel labgrid-client power get.

Something like following or something similar could possible happen:

Selected role main from configuration file
INFO         StepLogger:  → LinkPiSmartHUBPowerDriver.get()
INFO         StepLogger:  ⚠ LinkPiSmartHUBPowerDriver.get() [0.255s] exception=SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)')
Traceback (most recent call last):
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/remote/client.py", line 2304, in main
    args.func(session)
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/remote/client.py", line 980, in power
    res = getattr(drv, action)()
          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/binding.py", line 102, in wrapper
    return func(self, *_args, **_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/step.py", line 215, in wrapper
    _result = func(*_args, **_kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/driver/powerdriver.py", line 107, in get
    return self.proxy.get(self.port.path, self.port.index)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/util/agentwrapper.py", line 29, in __call__
    return self.wrapper.call(self.name, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/labgrid/lib/python3.12/site-packages/labgrid/util/agentwrapper.py", line 107, in call
    raise AgentException(e)
labgrid.util.agentwrapper.AgentException: SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)')

In above scenario there was likely two simultaneous serial.open() but only one could serial.readline() and succeeded or in worst case possible returned wrong power status.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was also able to trigger similar error using labgrid-client power cycle:

Selected role main from configuration file
INFO         StepLogger:  → LinkPiSmartHUBPowerDriver.cycle()
INFO         StepLogger:   → LinkPiSmartHUBPowerDriver.off()
INFO         StepLogger:   ← LinkPiSmartHUBPowerDriver.off() [0.138s]
INFO         StepLogger:   → LinkPiSmartHUBPowerDriver.on()
INFO         StepLogger:   ⚠ LinkPiSmartHUBPowerDriver.on() [1.006s] exception=SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)')
INFO         StepLogger:  ⚠ LinkPiSmartHUBPowerDriver.cycle() [3.145s] exception=SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)')

LinkPi SmartHUB is a 12-port USB3.0 HUB utilizing four RTS5411 USB3.0
4-port HUB controllers, a FT232R USB UART IC and a STM32F103RB MCU for
port power control.

Add a LinkPiSmartHUBPowerPort resource and a LinkPiSmartHUBPowerDriver
with an accompanying linkpismarthub agent to support power on/off the
ports of the LinkPi SmartHUB using a simple line-based protocol over a
serial port.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
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.

2 participants