What Andreas coded it’s an example of what I’d like to re-create in Python, basically setting a static IP Address on a Camera that is or is not in my subnet.
Changing one by one with the GenICam software it is easy, but I would like to automate the process thanks to a Network Switch and Python, in order to get the job done quicker and spend energies and resources on something else in the meantime.
I have tried to code something similar, but without success.
I have not found much on the documentation unfortunately (or maybe it’s just me being blind).
Does anybody know how to solve this one?
Many thanks,
Forgot to mention that I am working with cvbpy 1.5, on python 3.10.9 (conda) and CVB 14.00.002 on Windows.
I believe part of my code may be incorrect, also I do believe it is incorrect to open the device with the access token, but as the first link and your link suggest, the interface needs to be accessed instead.
import os
import time
import ipaddress
import socket
import cvb
cameras = {}
print("Looking for Cameras...")
iflags = cvb.DiscoverFlags.UpToLevelInterface | cvb.DiscoverFlags.IgnoreGevSD
all_interfaces = cvb.DeviceFactory.discover_from_root(iflags)
bflags = (cvb.DiscoverFlags.IgnoreVins | cvb.DiscoverFlags.IncludeInaccessible | cvb.DiscoverFlags.IgnoreGevSD)
for interface in all_interfaces:
cvb.DiscoveryInformation.set_genapi_feature(interface, "TLInterface", "DisableSubnetMatch", "1")
cvb.DiscoveryInformation.set_genapi_feature(interface, "TLInterface", "AllowBroadcastDiscoveryResponse", "1")
found_devices = cvb.DeviceFactory.discover_from_level(interface.access_token, bflags)
if len(found_devices) > 0:
print(f"{len(found_devices)} devices discovered.")
for i in range(len(found_devices)):
access = found_devices[i].access_token
devsn = found_devices[i].read_property(cvb.DiscoveryProperties.DeviceSerialNumber)
devip = found_devices[i].read_property(cvb.DiscoveryProperties.DeviceIP)
devmac = found_devices[i].read_property(cvb.DiscoveryProperties.DeviceMac)
accstat = found_devices[i].read_property(cvb.DiscoveryProperties.DeviceAccessStatus)
if devip not in [camera_info["IP"] for camera_info in cameras.values()]:
camera_name = f"cam{len(cameras)}"
cameras[camera_name] = {"SN": devsn, "IP": devip, "MAC": devmac, "Access Status":accstat}
for i, camera in enumerate(cameras, start=1):
print(f"{i}. Camera {camera}: {cameras[camera]}")
print("")
choice = input("Choose a camera (1-{}), or press 'Enter' to rescan: ".format(len(cameras)))
if choice.isdigit() and 1 <= int(choice) <= len(cameras):
camera_name = "cam{}".format(int(choice)-1)
print("You selected {}.".format(cameras[camera_name]["SN"]))
print("")
time.sleep(1)
os.system("cls")
#rest of my code....
#snippet
elif mchoice == "15":
ipconst = "10.2"
room_n = int(input("Enter the Room number: "))
if room_n < 10:
room = f".10{room_n}"
elif room_n >= 40:
print("Number is too great")
else:
room = f".1{room_n}"
camera_number = int(input("Enter the camera number (0-5): "))
if camera_number == 0:
cam = ".11"
elif camera_number == 1:
cam = ".12"
elif camera_number == 2:
cam = ".13"
elif camera_number == 3:
cam = ".14"
elif camera_number == 4:
cam = ".15"
elif camera_number == 5:
cam = ".16"
else:
print("Invalid camera number")
time.sleep(1)
ip = ipconst + room + cam
subnet = "255.255.255.0"
ip_address = ipaddress.ip_address(ip)
sub_address = ipaddress.ip_address(subnet)
hex_ip = socket.inet_aton(str(ip_address)).hex()
hex_sub = socket.inet_aton(str(sub_address)).hex()
print(ip)
print(hex_ip)
print(hex_sub)
with cvb.DeviceFactory.open(access) as device:
deviceUpdateListNode = cvb.CommandNode("DeviceUpdateList")
cfgIPNode = cvb.IntegerNode("IPCfg_IP")
cfgSubnetNode = cvb.IntegerNode("IPCfg_Subnet")
cfgForceNode = cvb.CommandNode("IPCfg_SetForceIP")
cfgStaticNode = cvb.CommandNode("IPCfg_SetStatIP")
deviceUpdateListNode.execute()
cfgIPNode.value(hex_ip)
cfgSubnetNode.value(hex_sub)
cfgForceNode.execute()
deviceUpdateListNode.execute()
cfgStaticNode.execute()
print("IP address Flashed: " + ip)
time.sleep(2)
os.system("cls")
time.sleep(1)
I think the issue is caused by the following lines of your code:
with cvb.DeviceFactory.open(access) as device:
deviceUpdateListNode = cvb.CommandNode("DeviceUpdateList")
cfgIPNode = cvb.IntegerNode("IPCfg_IP")
cfgSubnetNode = cvb.IntegerNode("IPCfg_Subnet")
cfgForceNode = cvb.CommandNode("IPCfg_SetForceIP")
cfgStaticNode = cvb.CommandNode("IPCfg_SetStatIP")
Here, you create new Command/Integer Nodes, but they aren’t referenced to any device.
If you have a look at the C# example I sent you, there is a method called ‘ForceIP’ that does the same thing, but it gets the nodes from the passed-in ‘iface’ NodeMap. This way it should be referenced
var ifaceToOpen = allInterfaces
.First(iface => iface[DiscoveryProperties.InterfaceId] == cam[DiscoveryProperties.InterfaceId]);
using (var ifaceDevice = DeviceFactory.Open(ifaceToOpen))
{
ForceIP(ifaceDevice.NodeMaps[NodeMapNames.Interface], cam, newIP);
}
static void ForceIP(NodeMap iface, DiscoveryInformation camera, IPAddress newIP)
{
var macAddress = PhysicalAddress.Parse(camera[DiscoveryProperties.DeviceMac]);
var subnet = GetInterfaceSubnetMask(camera);
var updateDeviceList = iface["DeviceUpdateList"] as CommandNode;
updateDeviceList.Execute();
var cfgMac = iface["IPCfg_MAC"] as IntegerNode;
cfgMac.Value = MacToInt(macAddress);
var cfgIP = iface["IPCfg_IP"] as IntegerNode;
cfgIP.Value = IPToInt(newIP);
var cfgSubnet = iface["IPCfg_Subnet"] as IntegerNode;
cfgSubnet.Value = IPToInt(subnet);
var cfgForceIP = iface["IPCfg_SetForceIP"] as CommandNode;
cfgForceIP.Execute();
}
In Python, you’ll access the needed Nodemap with the following code:
Sorry for the long wait, been on and off multiple projects!
I have tried your resolution and followed your advice.
I have also adapted your example to my code to match it and make it work the way intended.
Unfortunately, none of the node maps really changed, the IP/Subnet/gateway stay 0.0.0.0 on:
IPCfg_IP / IPCfg_Subnet and IPCfg_Gateway even by doing it manually via GenICam browser.
By using the access token “access = found_devices[i].access_token” the code you provided me runs just fine, but yet no change on IP address of the actual camera.
access = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=0)
RuntimeError: C-API call failed; try getting a log by using CVB LogGUI/silogutil: {"Name": "LoadImageFileW", "CVC_ERROR_CODE": 1}
While on LogGUI I don’t see any logs.
Now I am wondering if there is a way to change the IP address without accessing the camera nodemaps, the same way I do manually by right-clicking the camera in GenICam Browser and selecting Assign IP, as the nodemaps related to them are all read-only if the camera is accessed via token.
Basically, instead of editing the nodemaps, I will edit what’s in the NIC.
Sorry for the delayed response. I was out of the office
I think you identified the problem in the last line. As of my knowledge, if your NIC is set to DHCP, you can’t set a persistent static IP that is outside of your network range. If you set the desired range in your NIC, the code should work.