Skip to content

Skip VW query on STAR channels with firmware <= 2015 (fixes #1004)#1005

Merged
rickwierenga merged 2 commits intomainfrom
fix/pip-channel-info-legacy-firmware-1004
Apr 22, 2026
Merged

Skip VW query on STAR channels with firmware <= 2015 (fixes #1004)#1005
rickwierenga merged 2 commits intomainfrom
fix/pip-channel-info-legacy-firmware-1004

Conversation

@rickwierenga
Copy link
Copy Markdown
Member

Summary

Fixes #1004.

Test plan

  • lh.setup(skip_autoload=True) succeeds on a STARlet with April 2015 firmware (no VW sent, _pip_channel_information is None).
  • On a modern STAR, _pip_channel_information is a list of length num_channels after setup.
  • Existing STAR unit tests still pass.

🤖 Generated with Claude Code

The unconditional VW query from #991 fails on older STARlets (e.g. April
2015 firmware) with er30 "Unknown command", breaking lh.setup(). Probe
channel-0 firmware year first: leave _pip_channel_information as None
when unsupported, otherwise populate the full per-channel list. Fixes #1004.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@har1eyk
Copy link
Copy Markdown
Contributor

har1eyk commented Apr 22, 2026

Still errs for me:

STARFirmwareError                         Traceback (most recent call last)
/tmp/ipykernel_22268/2660497612.py in ?()
----> 1 await lh.setup(skip_autoload=True)
      2 
      3 # STARlet without iSWAP reports 0 arms; keep Co-Re gripper bookkeeping available.
      4 # if lh.backend.num_arms == 0:

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/liquid_handler.py in ?(self, **backend_kwargs)
    162       raise RuntimeError("The setup has already finished. See `LiquidHandler.stop`.")
    163 
    164     self.backend.set_deck(self.deck)
    165     self.backend.set_heads(head=self.head, head96=self.head96)
--> 166     await super().setup(**backend_kwargs)
    167 
    168     self.head = {c: TipTracker(thing=f"Channel {c}") for c in range(self.backend.num_channels)}
    169 

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/machines/machine.py in ?(self, **backend_kwargs)
     63   async def setup(self, **backend_kwargs):
---> 64     await self.backend.setup(**backend_kwargs)
     65     self._setup_finished = True

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/STAR_backend.py in ?(self, skip_instrument_initialization, skip_pip, skip_autoload, skip_iswap, skip_core96_head)
   1775       await set_up_pip()
   1776       await set_up_iswap()
   1777       await set_up_core96_head()
   1778 
-> 1779     await asyncio.gather(set_up_autoload(), set_up_arm_modules())
   1780 
   1781     # After setup, STAR will have thrown out anything mounted on the pipetting channels, including
   1782     # the core grippers.

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/STAR_backend.py in ?()
   1774     async def set_up_arm_modules():
-> 1775       await set_up_pip()
   1776       await set_up_iswap()
   1777       await set_up_core96_head()

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/STAR_backend.py in ?()
   1725       pip_fw = self._parse_firmware_version_datetime(await self.request_pip_channel_version(0))
   1726       if pip_fw.year <= 2015:
   1727         self._pip_channel_information = None
   1728       else:
-> 1729         self._pip_channel_information = [
   1730           await self._pip_channel_request_configuration(ch) for ch in range(self.num_channels)
   1731         ]

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/STAR_backend.py in ?(self, channel)
   1535 
   1536     Args:
   1537       channel: 0-indexed channel number.
   1538     """
-> 1539     resp: str = await self.send_command(STARBackend.channel_id(channel), "VW")
   1540     hw_tokens = resp.split("vw")[-1].strip().split()
   1541     return PipChannelInformation(
   1542       channel_type="ML_STAR_RPC" if hw_tokens[0] == "1" else "ML_STAR",

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/base.py in ?(self, module, command, auto_id, tip_pattern, write_timeout, read_timeout, wait, fmt, **kwargs)
    262       tip_pattern=tip_pattern,
    263       auto_id=auto_id,
    264       **kwargs,
    265     )
--> 266     resp = await self._write_and_read_command(
    267       id_=id_,
    268       cmd=cmd,
    269       write_timeout=write_timeout,

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/base.py in ?(self, id_, cmd, write_timeout, read_timeout, wait)
    294 
    295     loop = asyncio.get_event_loop()
    296     fut: asyncio.Future[str] = loop.create_future()
    297     self._start_reading(id_, loop, fut, cmd, read_timeout)
--> 298     result = await fut
    299     return result

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/base.py in ?(self)
    358           )
    359           del self._waiting_tasks[idx]
    360 
    361       if len(self._waiting_tasks) == 0:
--> 362         await asyncio.sleep(0.01)
    363         continue
    364 
    365       try:

~/Documents/Hamilton-Starlet/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/STAR_backend.py in ?(self, resp)
   1635           he.errors[
   1636             module_name
   1637           ].message += " (call lh.backend.request_name_of_last_faulty_parameter)"
   1638 
-> 1639       raise he

STARFirmwareError: {'Pipetting channel 1': UnknownHamiltonError('Unknown command')}, P1VWid0016er30```

@rickwierenga
Copy link
Copy Markdown
Member Author

what is pip_fw? it doesn't hit the if pip_fw.year <= 2015: branch

@har1eyk
Copy link
Copy Markdown
Contributor

har1eyk commented Apr 22, 2026

what is pip_fw? it doesn't hit the if pip_fw.year <= 2015: branch

print(await lh.backend.request_firmware_version())
fw_str = await lh.backend.request_pip_channel_version(0)
print (fw_str)
pip_fw = lh.backend._parse_firmware_version_datetime(fw_str)
print (f"Firmware version: {pip_fw}")```

C0RFid0029er00/00rf7.2S D 2015-04-01
3.9S f 2016-06-02
Firmware version: 2016-06-02


Two different firmware versions?

@rickwierenga
Copy link
Copy Markdown
Member Author

ah I see. Yes the PIP channels have their own chips and firmware versions which are different from C0 (the master module). Same for 96 head and autoload and iswap etc. they all have their own version

Bumps the VW cutoff from 2015 to 2016 and fails fast inside the
per-channel helper so the command is never sent on unsupported firmware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rickwierenga
Copy link
Copy Markdown
Member Author

does this work @har1eyk

@har1eyk
Copy link
Copy Markdown
Contributor

har1eyk commented Apr 22, 2026

does this work @har1eyk

Success! Many thanks.

@rickwierenga rickwierenga merged commit 2e37e1e into main Apr 22, 2026
21 checks passed
@rickwierenga
Copy link
Copy Markdown
Member Author

thanks for report and testing!

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.

STARlet older firmware fails setup after VW query added in c4fe7e6 (#991)

2 participants