Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved poe_set_ip.py script usage and reduced chance of errors. #1008

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions docs/source/samples/bootloader/poe_set_ip.rst
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
POE set IP
==========

This script allows you to set static or dynamic IP, or clear bootloader config on your OAK-POE device.
This script allows you to set static or dynamic IP, get the currently set IP, or clear bootloader config on your OAK-POE device.

.. warning::
Make sure to **set mask and gateway correctly!** If they are set incorrectly you will soft-brick your
device (you won't be able to access it), and will have to `factory reset <https://docs.luxonis.com/projects/hardware/en/latest/pages/guides/getting-started-with-poe.html#factory-reset>`__
your OAK PoE.

.. note::
The script currently doesn't support setting a IPv6 address.
We suggest using :ref:`Device Manager`, a GUI tool for interfacing with the bootloader and its configurations.

Demo
####

Example script output:

Use cases:
.. code-block:: bash
# Set a static IPv4
python3 poe_set_ip.py static <static IPv4 to set> <mask>
# Set a static IPv4 and gateway
python3 poe_set_ip.py static <static IPv4 to set> <mask> --gateway <Gateway IPv4>
# Set a dynamic IPv4 and gateway
python3 poe_set_ip.py dynamic <dynamic IPv4 to set> <mask> --gateway <Gateway IPv4>
# Get the currently set IPv4
python3 poe_set_ip.py get

Found device with name: 192.168.1.136
-------------------------------------
"1" to set a static IPv4 address
"2" to set a dynamic IPv4 address
"3" to clear the config
1
Example of how to set a static IPv4 address:

.. code-block:: bash
python3 poe_set_ip.py static 192.168.1.200 255.255.255.0 --gateway 192.168.1.1
-------------------------------------
Enter IPv4: 192.168.1.200
Enter IPv4 Mask: 255.255.255.0
Enter IPv4 Gateway: 192.168.1.1
Flashing static IPv4 192.168.1.200, mask 255.255.255.0, gateway 192.168.1.1 to the POE device. Enter 'y' to confirm. y
Flashing successful.

If you run the same example again after 10 seconds, you will see that IP changed to **192.168.1.200**:
If you run the same example again after 10 seconds, you verify that the IP was changed to **192.168.1.200**:

.. code-block:: bash

Found device with name: 192.168.1.200
python3 poe_set_ip.py get
-------------------------------------
"1" to set a static IPv4 address
"2" to set a dynamic IPv4 address
"3" to clear the config
Device (IPv4): 192.168.1.200, Mask: 255.255.255.0, Gateway: 192.168.1.1

You can now also use the `Manually specify device IP <https://docs.luxonis.com/projects/hardware/en/latest/pages/guides/getting-started-with-poe.html#manually-specify-device-ip>`__
script and change the IP to :code:`192.168.1.200`.
Expand Down
135 changes: 101 additions & 34 deletions examples/bootloader/poe_set_ip.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,112 @@
import depthai as dai

(found, info) = dai.DeviceBootloader.getFirstAvailableDevice()

def check_str(s: str):
spl = s.split(".")
if len(spl) != 4:
raise ValueError(f"Entered value {s} doesn't contain 3 dots. Value has to be in the following format: '255.255.255.255'")
for num in spl:
if 255 < int(num):
raise ValueError("Entered values can't be above 255!")
return s

if found:
print(f'Found device with name: {info.name}')
print('-------------------------------------')
print('"1" to set a static IPv4 address')
print('"2" to set a dynamic IPv4 address')
print('"3" to clear the config')
key = input('Enter the number: ').strip()
print('-------------------------------------')
if int(key) < 1 or 3 < int(key):
raise ValueError("Entered value should either be '1', '2' or '3'!")
import argparse
from enum import Enum
from ipaddress import ip_address, ip_network

with dai.DeviceBootloader(info) as bl:
if key in ['1', '2']:
ipv4 = check_str(input("Enter IPv4: ").strip())
mask = check_str(input("Enter IPv4 Mask: ").strip())
gateway = check_str(input("Enter IPv4 Gateway: ").strip())
mode = 'static' if key == '1' else 'dynamic'
val = input(f"Flashing {mode} IPv4 {ipv4}, mask {mask}, gateway {gateway} to the POE device. Enter 'y' to confirm. ").strip()
if val != 'y':
raise Exception("Flashing aborted.")

class Modes(str, Enum):
IP_STATIC = "static"
IP_DYNAMIC = "dynamic"
CLEAR = "clear"
GET = "get"


def str_to_ip(ip: str) -> int:
"""Converts an IPv4 string to an integer."""
return sum([int(x) << (8 * i) for i, x in enumerate(ip.split("."))])


def main(mode: Modes, ip: str = "", mask: str = "", gateway: str = "") -> None:
(found, info) = dai.DeviceBootloader.getFirstAvailableDevice()
if not found:
raise ValueError("No device found!")
# TODO: Support IPv6
with dai.DeviceBootloader(info) as bl:
try:
# Read config, if it exists
conf = bl.readConfig()
except RuntimeError:
# Create a default config if one doesn't exist
conf = dai.DeviceBootloader.Config()
if key == '1': conf.setStaticIPv4(ipv4, mask, gateway)
elif key == '2': conf.setDynamicIPv4(ipv4, mask, gateway)

if mode == Modes.GET:
print(
f"Device (IPv4): {conf.getIPv4()}, Mask: {conf.getIPv4Mask()}, Gateway: {conf.getIPv4Gateway()}"
)
return
if mode in {Modes.IP_STATIC, Modes.IP_DYNAMIC}:
is_ip_static = mode == Modes.IP_STATIC
if not gateway:
conf_d = conf.toJson()
conf_d.update(
{
"network": {
"ipv4": str_to_ip(ip),
"ipv4Mask": str_to_ip(mask),
"staticIpv4": is_ip_static,
}
}
)
conf = dai.DeviceBootloader.Config.fromJson(conf_d)
else:
set_ip = conf.setStaticIPv4 if is_ip_static else conf.setDynamicIPv4
set_ip(ip, mask, gateway)
(success, error) = bl.flashConfig(conf)
elif key == '3':
else:
(success, error) = bl.flashConfigClear()

if not success:
print(f"Flashing failed: {error}")
else:
print(f"Flashing successful.")
print(f"Flashing successful.")


if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="PoE set IP",
description="You can set a static, dynamic IPv4 of the device or clear the flash config.",
)
subparsers = parser.add_subparsers(dest="mode", required=True, help="Choose a mode")
validate_ip = lambda ip: str(ip_address(ip))

ip_parser = subparsers.add_parser(
Modes.IP_STATIC.value, description="Set a static IPv4 address"
)
ip_parser.add_argument("ip", type=validate_ip, help="Device IPv4 address")
ip_parser.add_argument("mask", type=validate_ip, help="Network mask")
ip_parser.add_argument(
"-g", "--gateway", type=validate_ip, help="Gateway IPv4 address"
)
ip_parser = subparsers.add_parser(
Modes.IP_DYNAMIC.value, description="Set a dynamic IPv4 address"
)
ip_parser.add_argument("ip", type=validate_ip, help="Device IPv4 address")
ip_parser.add_argument("mask", type=validate_ip, help="Network mask")
ip_parser.add_argument(
"-g", "--gateway", type=validate_ip, help="Gateway IPv4 address"
)
ip_parser = subparsers.add_parser(
Modes.CLEAR.value, description="Clear flash configuration"
)
ip_parser = subparsers.add_parser(
Modes.GET.value, description="Get IP configuration"
)
args = parser.parse_args()

# Check if device IP is on the same network as the gateway
if (
hasattr(args, "gateway")
and args.gateway
and args.mode in {Modes.IP_STATIC, Modes.IP_DYNAMIC}
):
device_ip = ip_address(args.ip)
mask = ip_address(args.mask)
gateway = ip_address(args.gateway)

network_ip = ip_address(int(gateway) & int(mask))
network = ip_network(f"{network_ip}/{mask}")
if not device_ip in network:
raise ValueError("Device IP doesn't belong in the same network as gateway!")

main(**vars(args))