Open EvanKirshenbaum opened 5 months ago
This issue was referenced by the following commit before migration:
Ah. It looks as though what I need is socket.getaddrinfo()
.
I should be able to work with that.
Since it's me, there's now a general solution.
First, I added an erk.network
module with the following:
def ip_addr_as_int(addr: str) -> int: ...
def int_to_ip_addr(ip: int) -> str: ...
def canonicalize_ip_addr(addr: str) -> str: ...
def local_ipv4_addrs(*, subnet: Optional[str] = None,
subnet_mask: Optional[str] = None) -> Sequence[str]: ...
def local_ipv4_addr(*,
addr: Optional[str] = None,
subnet: Optional[str] = None,
subnet_mask: Optional[str] = None
) -> Optional[str]: ...
local_ipv4_addrs()
returns a (possibly empty) list of all local IP addresses (as canonicalized strings) or those that match the given subnet
using the given subnet_mask
. The subnet
doesn't have to be a full quad. Trailing zeroes are inferred. If it isn't a full quad and the subnet_mask
is None
, a subnet_mask
will be inferred with a 255
for every explicit place in subnet
. (That means, for example, that a subnet
of "192.168"
will have a default subnet_mask
of "255.255.0.0"
, while a subnet
of "192.168.0"
will have a default subnet_mask
of "255.255.255.0"
.)
local_ipv4_addr()
returns a single address (unless there are no addresses, in which case it returns None
). If addr
is given, it is returned, and a warning is logged if it isn't among the local addresses. If subnet
is given and there's a single local address on that subnet (given the mask), it's returned. If there are multiple addresses on the subnet, a warning is logged, and the first matching address is returned. If there are no addresses on that subnet, a warning is logged and the first local address is returned. If neither addr
nor subnet
is provided, the first local address is returned and a warning is logged if there are more than one of them.
Next, I added --local-ip
, local-subnet
, and --subnet-mask
command-line arguments to provide the values to pass to local_ipv4_addr()
if the config file doesn't specify endpoint
information. To support that, I added ip_addr_arg
and ip_subnet_arg
types to cmd_line.py
. (Oh, yeah, I abstracted out command-line types to a separate module.) These actually are used by System
, which now has a local_ipv4_addr
property, so the same IP address will be handed out to any component that needs to run a listener.
The code works on my machine, but it only has one IP address. I've asked [comment by @EvanKirshenbaum on Oct 10, 2022 at 4:43 PM PDT] Mark Huber to try it out on his machine, which has multiple and which led to our noticing the problem.
it works, i took out the hardcoded ip and ran it with the local-ip argument, it worked. I did not see a warning though:
python cs.py joey --pipettor ot2 --ot-ip 192.168.1.113 --ot-config ../inputs/ot2.json --ot-reagents ../inputs/reagents.json --clock-speed=100ms --fragments 20 --shuttles=2 --cycles=2 --local-ip 192.168.1.117
Platform option 'devices.bilby.PlatformTask' requires 'pyglider' module, ignoring
INFO|opentrons|Launching listener
======== Running on http://0.0.0.0:8087 ========
(Press CTRL+C to quit)
INFO|opentrons|Listening for OT-2 on 192.168.1.117:8087
INFO|opentrons|Temp protocol file is C:\Users\huberma\AppData\Local\Temp\protocol_pz7chrop.py
INFO|opentrons|Create Protocol result: {'data': {'id': 'c5868978-6638-4fba-9e06-c4b3fdc6fb95', 'createdAt': '2022-10-13T21:27:54.836499+00:00', 'files': [{'name': 'protocol_pz7chrop.py', 'role': 'main'}], 'protocolType': 'python', 'metadata': {'description': 'A generic looping client to use the OT-2 as a peripheral for Joey', 'apiLevel': '2.11', 'protocolName': 'Joey Peripheral Protocol', 'author': 'Evan Kirshenbaum < evan.kirshenbaum@hp.com>'}, 'analyses': [], 'analysisSummaries': [{'id': '59aeb8e1-cc11-4332-9121-1548276683b7', 'status': 'pending'}]}}
INFO|opentrons|Created protocol "c5868978-6638-4fba-9e06-c4b3fdc6fb95".
INFO|opentrons|Created session "28ad82e4-44ab-4f1d-975f-37e8a10a9b38".
INFO|opentrons|Started run.
INFO|pipettor|Pipettor("OT-2") is not idle
INFO|monitor|Setting tick to 100.0 ms
OT-2 [14:28:19]: Creating the robot. Callback endpoint is http://192.168.1.117:8087
OT-2 [14:28:51]: Board labware spec is {'name': 'biorad_96_wellplate_200ul_pcr', 'slot': 8}
OT-2 [14:28:51]: Board plate is Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:51]: Board drop size is 1.0
OT-2 [14:28:51]: Board wells is [E1 of Bio-Rad 96 Well Plate 200 µL PCR on 8, F1 of Bio-Rad 96 Well Plate 200 µL PCR on 8, G1 of Bio-Rad 96 Well Plate 200 µL PCR on 8, H1 of Bio-Rad 96 Well Plate 200 µL PCR on 8, E5 of Bio-Rad 96 Well Plate 200 µL PCR on 8, F5 of Bio-Rad 96 Well Plate 200 µL PCR on 8, G5 of Bio-Rad 96 Well Plate 200 µL PCR on 8, H5 of Bio-Rad 96 Well Plate 200 µL PCR on 8]
OT-2 [14:28:51]: Board extraction_ports is [E3 of Bio-Rad 96 Well Plate 200 µL PCR on 8, F3 of Bio-Rad 96 Well Plate 200 µL PCR on 8, G3 of Bio-Rad 96 Well Plate 200 µL PCR on 8]
OT-2 [14:28:51]: Board oil_reservoir is A3 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:51]: Done creating board
OT-2 [14:28:56]: Created robot and board
OT-2 [14:28:56]: W1: E1 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W2: F1 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W3: G1 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W4: H1 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W5: E5 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W6: F5 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W7: G5 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: W8: H5 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: E1: E3 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: E2: F3 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: E3: G3 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: O1: A3 of Bio-Rad 96 Well Plate 200 µL PCR on 8
OT-2 [14:28:56]: Starting run
OT-2 [14:28:56]: http://192.168.1.117:8087
OT-2 [14:28:56]: Entering main loop
OT-2 [14:28:56]: Making ready call
OT-2 [14:28:56]: Calling ready: {}
OT-2 [14:28:56]: Back from ready: <Response [200]>
OT-2 [14:28:56]: -------------------
OT-2 [14:28:57]: supplying PM Primers: 10.0 µL @ W5
it works, i took out the hardcoded ip and ran it with the local-ip argument, it worked. I did not see a warning though:
You'll only get the warning if you don't give an argument or if you give a --local-subnet
argument that isn't specific enough to narrow it down.
Could you try running it again with the following options?
--local-subnet 192.168
. You should get a warning, and it should pick the wrong one (since all the options match that prefix).--local-subnet 192.168.1
. It should pick the right one, and you shouldn't get a warning.
Originally posted by @EvanKirshenbaum in https://github.com/HPInc/HP-Digital-Microfluidics/issues/201 [comment by @EvanKirshenbaum on Oct 07, 2022 at 11:49 AM PDT]
To support the Opentrons pipettor, we run a local HTTP server and tell the robot where to call back to. To obtain the IP address, we run
When Mark Huber ran this, the robot was unable to connect to his machine. It turns out that the problem was that his machine had two IP addresses: 192.168.1.117 over Wi-Fi and 192.168.223.1 using a VMWare network adapter. Even though the virtual machine wasn't running, the above code was picking up that address, and the robot was unable to connect to it, since it wasn't on the same local network.
A simple fix would be to allow the user, when they realize that they are in this situation, to specify a local IP address on the command line, but this is unsatisfying, as it requires the user to know what their problem is. Better would be to somehow detect that there are multiple possibilities and either refuse to run if the user doesn't specify or at least print a warning that this might be a problem and pick one to use by default.
Note that even now, the IP address can be specified in the JSON config file. (The above code only runs if it isn't specified there.)
Migrated from internal repository. Originally created by @EvanKirshenbaum on Oct 07, 2022 at 11:50 AM PDT.