Source code for snap7.discovery

"""
PROFINET DCP network discovery for finding Siemens PLCs.

Uses the pnio-dcp library for the underlying DCP protocol.
Install with: pip install python-snap7[discovery]
"""

from __future__ import annotations

import dataclasses
import logging

logger = logging.getLogger(__name__)


[docs] @dataclasses.dataclass(frozen=True) class Device: """A discovered PROFINET device on the network.""" name: str ip: str mac: str netmask: str = "" gateway: str = "" family: str = "" def __str__(self) -> str: return f"{self.name} ({self.ip}) [{self.mac}]"
[docs] def discover(ip: str, timeout: float = 5.0) -> list[Device]: """Discover PROFINET devices on the network using DCP Identify All. Args: ip: IP address of the local network interface to use for discovery. timeout: How long to listen for responses in seconds (default 5.0). Returns: List of discovered devices. Raises: ImportError: If pnio-dcp is not installed. NotImplementedError: If the current platform is not supported by pnio-dcp. """ try: from pnio_dcp import DCP except ImportError: raise ImportError("pnio-dcp is required for network discovery. Install it with: pip install python-snap7[discovery]") dcp = DCP(ip) dcp.identify_all_timeout = int(timeout) if timeout >= 1 else 1 raw_devices = dcp.identify_all(timeout=int(timeout) if timeout >= 1 else 1) devices = [] for raw in raw_devices: device = Device( name=raw.name_of_station, ip=raw.IP, mac=raw.MAC, netmask=getattr(raw, "netmask", ""), gateway=getattr(raw, "gateway", ""), family=getattr(raw, "family", ""), ) devices.append(device) logger.debug(f"Discovered: {device}") logger.info(f"Discovery complete: found {len(devices)} device(s)") return devices
[docs] def identify(ip: str, mac: str) -> Device: """Identify a specific device by MAC address. Args: ip: IP address of the local network interface to use. mac: MAC address of the target device (colon-separated, e.g. "00:1b:1b:12:34:56"). Returns: The identified device. Raises: ImportError: If pnio-dcp is not installed. TimeoutError: If the device does not respond. """ try: from pnio_dcp import DCP, DcpTimeoutError except ImportError: raise ImportError("pnio-dcp is required for network discovery. Install it with: pip install python-snap7[discovery]") dcp = DCP(ip) try: raw = dcp.identify(mac) except DcpTimeoutError: raise TimeoutError(f"No response from device {mac}") return Device( name=raw.name_of_station, ip=raw.IP, mac=raw.MAC, netmask=getattr(raw, "netmask", ""), gateway=getattr(raw, "gateway", ""), family=getattr(raw, "family", ""), )
try: import click @click.command() @click.argument("ip") @click.option("--timeout", type=float, default=5.0, help="Discovery timeout in seconds.") def discover_command(ip: str, timeout: float) -> None: """Discover PROFINET devices on the network. IP is the address of the local network interface to use for discovery. Requires pnio-dcp: pip install python-snap7[discovery] """ try: devices = discover(ip, timeout) except ImportError as e: click.echo(str(e), err=True) raise SystemExit(1) except NotImplementedError as e: click.echo(f"Platform not supported: {e}", err=True) raise SystemExit(1) if not devices: click.echo("No devices found.") return click.echo(f"Found {len(devices)} device(s):\n") for device in devices: click.echo(f" {device.name:<30s} {device.ip:<16s} {device.mac}") except ImportError: pass