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

Add network configuration #271

Merged
merged 1 commit into from
Jun 28, 2024
Merged
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
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ per-file-ignores =
camera_info.py:D101,D102,D106,D107
camera_intrinsics.py:D101,D102,D106,D107
frame_info.py:D101,D102,D106,D107
network_configuration.py:D101,D102,D106,D107
1 change: 1 addition & 0 deletions .pylintrc-tests
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ disable=missing-docstring,
pointless-statement,
too-many-lines,
too-many-statements,
too-few-public-methods,
consider-using-f-string # Keep .format() as long as we want unofficial python3.5 support

[FORMAT]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,7 @@ def generate_all_datamodels(dest_dir: Path) -> None:
["datetime"],
),
(_zivid.CameraIntrinsics, "camera_intrinsics.py", []),
(_zivid.NetworkConfiguration, "network_configuration.py", []),
]:
_generate_datamodel_frontend(
internal_class=internal_class,
Expand Down
1 change: 1 addition & 0 deletions modules/_zivid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
CameraInfo,
infield_correction,
Matrix4x4,
NetworkConfiguration,
data_model,
PixelMapping,
projection,
Expand Down
1 change: 1 addition & 0 deletions modules/zivid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
from zivid.camera_info import CameraInfo
from zivid.camera_intrinsics import CameraIntrinsics
from zivid.matrix4x4 import Matrix4x4
from zivid.network_configuration import NetworkConfiguration
55 changes: 53 additions & 2 deletions modules/zivid/camera.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
"""Contains Camera class."""
import _zivid
from zivid.camera_info import _to_camera_info
from zivid.camera_state import _to_camera_state
from zivid.frame import Frame
from zivid.frame_2d import Frame2D
from zivid.network_configuration import (
NetworkConfiguration,
_to_internal_network_configuration,
_to_network_configuration,
)
from zivid.settings import Settings, _to_internal_settings
from zivid.settings_2d import Settings2D, _to_internal_settings2d
from zivid.camera_info import _to_camera_info
from zivid.camera_state import _to_camera_state


class Camera:
Expand Down Expand Up @@ -90,6 +95,52 @@ def disconnect(self):
"""Disconnect from the camera and free all resources associated with it."""
self.__impl.disconnect()

@property
def network_configuration(self):
"""Get the network configuration of the camera.

Returns:
NetworkConfiguration instance
"""
return _to_network_configuration(self.__impl.network_configuration)

def apply_network_configuration(self, network_configuration):
"""
Apply the network configuration to the camera.

Args:
network_configuration (NetworkConfiguration): The network configuration to apply to the camera.

This method blocks until the camera has finished applying the network configuration, or raises an exception if
the camera does not reappear on the network before a timeout occurs.

This method can be used even if the camera is inaccessible via TCP/IP, for example a camera that is on a
different subnet to the PC, or a camera with an IP conflict, as it uses UDP multicast to communicate with the
camera.

This method can also be used to configure cameras that require a firmware update, as long as the firmware
supports network configuration via UDP multicast. This has been supported on all firmware versions included
with SDK 2.10.0 or newer. This method will raise an exception if the camera firmware is too old to support
UDP multicast.

This method will raise an exception if the camera status (see CameraState.Status) is "busy", "connected",
"connecting" or "disconnecting". If the status is "connected", then you must first call disconnect() before
calling this method.

Raises:
TypeError: If the provided network_configuration is not an instance of NetworkConfiguration.
"""
if not isinstance(network_configuration, NetworkConfiguration):
raise TypeError(
"Unsupported type, expected: {expected_type}, got: {value_type}".format(
expected_type=NetworkConfiguration,
value_type=type(network_configuration),
)
)
self.__impl.apply_network_configuration(
_to_internal_network_configuration(network_configuration)
)

def write_user_data(self, user_data):
"""Write user data to camera. The total number of writes supported depends on camera model and size of data.

Expand Down
203 changes: 203 additions & 0 deletions modules/zivid/network_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"""Auto generated, do not edit."""
# pylint: disable=too-many-lines,protected-access,too-few-public-methods,too-many-arguments,line-too-long,missing-function-docstring,missing-class-docstring,redefined-builtin,too-many-branches,too-many-boolean-expressions
import _zivid


class NetworkConfiguration:
class IPV4:
class Mode:
dhcp = "dhcp"
manual = "manual"

_valid_values = {
"dhcp": _zivid.NetworkConfiguration.IPV4.Mode.dhcp,
"manual": _zivid.NetworkConfiguration.IPV4.Mode.manual,
}

@classmethod
def valid_values(cls):
return list(cls._valid_values.keys())

def __init__(
self,
address=_zivid.NetworkConfiguration.IPV4.Address().value,
mode=_zivid.NetworkConfiguration.IPV4.Mode().value,
subnet_mask=_zivid.NetworkConfiguration.IPV4.SubnetMask().value,
):
if isinstance(address, (str,)):
self._address = _zivid.NetworkConfiguration.IPV4.Address(address)
else:
raise TypeError(
"Unsupported type, expected: (str,), got {value_type}".format(
value_type=type(address)
)
)

if isinstance(mode, _zivid.NetworkConfiguration.IPV4.Mode.enum):
self._mode = _zivid.NetworkConfiguration.IPV4.Mode(mode)
elif isinstance(mode, str):
self._mode = _zivid.NetworkConfiguration.IPV4.Mode(
self.Mode._valid_values[mode]
)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(mode)
)
)

if isinstance(subnet_mask, (str,)):
self._subnet_mask = _zivid.NetworkConfiguration.IPV4.SubnetMask(
subnet_mask
)
else:
raise TypeError(
"Unsupported type, expected: (str,), got {value_type}".format(
value_type=type(subnet_mask)
)
)

@property
def address(self):
return self._address.value

@property
def mode(self):
if self._mode.value is None:
return None
for key, internal_value in self.Mode._valid_values.items():
if internal_value == self._mode.value:
return key
raise ValueError("Unsupported value {value}".format(value=self._mode))

@property
def subnet_mask(self):
return self._subnet_mask.value

@address.setter
def address(self, value):
if isinstance(value, (str,)):
self._address = _zivid.NetworkConfiguration.IPV4.Address(value)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(value)
)
)

@mode.setter
def mode(self, value):
if isinstance(value, str):
self._mode = _zivid.NetworkConfiguration.IPV4.Mode(
self.Mode._valid_values[value]
)
elif isinstance(value, _zivid.NetworkConfiguration.IPV4.Mode.enum):
self._mode = _zivid.NetworkConfiguration.IPV4.Mode(value)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(value)
)
)

@subnet_mask.setter
def subnet_mask(self, value):
if isinstance(value, (str,)):
self._subnet_mask = _zivid.NetworkConfiguration.IPV4.SubnetMask(value)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(value)
)
)

def __eq__(self, other):
if (
self._address == other._address
and self._mode == other._mode
and self._subnet_mask == other._subnet_mask
):
return True
return False

def __str__(self):
return str(_to_internal_network_configuration_ipv4(self))

def __init__(
self,
ipv4=None,
):
if ipv4 is None:
ipv4 = self.IPV4()
if not isinstance(ipv4, self.IPV4):
raise TypeError("Unsupported type: {value}".format(value=type(ipv4)))
self._ipv4 = ipv4

@property
def ipv4(self):
return self._ipv4

@ipv4.setter
def ipv4(self, value):
if not isinstance(value, self.IPV4):
raise TypeError("Unsupported type {value}".format(value=type(value)))
self._ipv4 = value

@classmethod
def load(cls, file_name):
return _to_network_configuration(_zivid.NetworkConfiguration(str(file_name)))

def save(self, file_name):
_to_internal_network_configuration(self).save(str(file_name))

@classmethod
def from_serialized(cls, value):
return _to_network_configuration(
_zivid.NetworkConfiguration.from_serialized(str(value))
)

def serialize(self):
return _to_internal_network_configuration(self).serialize()

def __eq__(self, other):
if self._ipv4 == other._ipv4:
return True
return False

def __str__(self):
return str(_to_internal_network_configuration(self))


def _to_network_configuration_ipv4(internal_ipv4):
return NetworkConfiguration.IPV4(
address=internal_ipv4.address.value,
mode=internal_ipv4.mode.value,
subnet_mask=internal_ipv4.subnet_mask.value,
)


def _to_network_configuration(internal_network_configuration):
return NetworkConfiguration(
ipv4=_to_network_configuration_ipv4(internal_network_configuration.ipv4),
)


def _to_internal_network_configuration_ipv4(ipv4):
internal_ipv4 = _zivid.NetworkConfiguration.IPV4()

internal_ipv4.address = _zivid.NetworkConfiguration.IPV4.Address(ipv4.address)
internal_ipv4.mode = _zivid.NetworkConfiguration.IPV4.Mode(ipv4._mode.value)
internal_ipv4.subnet_mask = _zivid.NetworkConfiguration.IPV4.SubnetMask(
ipv4.subnet_mask
)

return internal_ipv4


def _to_internal_network_configuration(network_configuration):
internal_network_configuration = _zivid.NetworkConfiguration()

internal_network_configuration.ipv4 = _to_internal_network_configuration_ipv4(
network_configuration.ipv4
)
return internal_network_configuration
65 changes: 65 additions & 0 deletions samples/sample_network_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Sample demonstrating network configuration of a Zivid camera."""
import zivid


def _confirm(message):
while True:
input_value = input(f"{message} [Y/n] ")
if input_value.lower() in ["y", "yes"]:
return True
if input_value.lower() in ["n", "no"]:
return False


def _main():
app = zivid.Application()
camera = app.cameras()[0]

original_config = camera.network_configuration

print(f"Current network configuration of camera {camera.info.serial_number}:")
print(original_config)
print()

mode = zivid.NetworkConfiguration.IPV4.Mode.manual
address = original_config.ipv4.address
subnet_mask = original_config.ipv4.subnet_mask

if _confirm("Do you want to use DHCP?"):
mode = zivid.NetworkConfiguration.IPV4.Mode.dhcp
else:
input_address = input(f"Enter IPv4 Address [{original_config.ipv4.address}]: ")
address = input_address if input_address else original_config.ipv4.address
input_subnet_mask = input(
f"Enter new Subnet mask [{original_config.ipv4.subnet_mask}]: "
)
subnet_mask = (
input_subnet_mask if input_subnet_mask else original_config.ipv4.subnet_mask
)

new_config = zivid.NetworkConfiguration(
ipv4=zivid.NetworkConfiguration.IPV4(
mode=mode,
address=address,
subnet_mask=subnet_mask,
)
)

print()
print("New network configuration:")
print(new_config)
if _confirm(
f"Do you want to apply the new network configuration to camera {camera.info.serial_number}?"
):
print("Applying network configuration...")
camera.apply_network_configuration(new_config)

print(f"Updated network configuration of camera {camera.info.serial_number}:")
print(camera.network_configuration)
print()

print(f"Camera status is '{camera.state.status}'")


if __name__ == "__main__":
_main()
4 changes: 3 additions & 1 deletion src/ReleasableCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ namespace ZividPython
.def_property_readonly("state", &ReleasableCamera::state)
.def_property_readonly("info", &ReleasableCamera::info)
.def("write_user_data", &ReleasableCamera::writeUserData)
.def_property_readonly("user_data", &ReleasableCamera::userData);
.def_property_readonly("user_data", &ReleasableCamera::userData)
.def_property_readonly("network_configuration", &ReleasableCamera::networkConfiguration)
.def("apply_network_configuration", &ReleasableCamera::applyNetworkConfiguration);
}
} // namespace ZividPython
1 change: 1 addition & 0 deletions src/Wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ZIVID_PYTHON_MODULE // NOLINT
ZIVID_PYTHON_WRAP_DATA_MODEL(module, CameraInfo);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, FrameInfo);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, CameraIntrinsics);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, NetworkConfiguration);

ZIVID_PYTHON_WRAP_CLASS_AS_SINGLETON(module, Application);
ZIVID_PYTHON_WRAP_CLASS_AS_RELEASABLE(module, Camera);
Expand Down
Loading