I am using 8.3.9 and am trying to use the function system.device.addDevice to add Modbus device connections from a CSV. All the devices have a Simulator connection inside connected to my dev Deployment Mode. Is there a way to specify which deployment mode I will be adding the device to instead of it defaulting to core? This way it won't fail because a device will already exist under that name.
If you need to target a specific deployment mode, you need to go to the system.config scripting functions:
It is, unfortunately, pretty verbose because we don't currently have a mechanism to "fold in" defaults provided by the underlying driver/configuration type.
Or another draft with the same base functionality as provided by Claude:
DEVICE_MODULE_ID = "com.inductiveautomation.opcua"
DEVICE_TYPE_ID = "device"
# The driver reads its address map from this resource data file. The format is the same as the CSV
# the Gateway's "Export CSV" button produces, but with the lines joined by '|' instead of newlines.
ADDRESS_MAP_KEY = "address-map.txt"
def csvToAddressMap(csvText):
"""
Converts the Gateway's address-map CSV export format to the stored address-map.txt format.
CSV layout (no header row):
line 1: designator radix, e.g. 10
line 2..: prefix,start,end,step,unitId,addressType,modbusStart
e.g. HR,1,100,false,1,HoldingRegister,1
addressType is the AddressType enum name (HoldingRegister, HoldingRegisterFloat, Coil,
DiscreteInput, InputRegisterUInt16, ...). Malformed rows are silently dropped by the driver.
"""
lines = [line.strip() for line in csvText.splitlines() if line.strip()]
return "|".join(lines)
def createModbusTcpDevice(
name,
hostname,
addressMapCsv=None,
collection=None,
port=502,
enabled=True,
description=None):
settings = {
"connectivity": {
"hostname": hostname,
"port": port,
"localAddress": "",
"communicationTimeout": 2000,
},
"requestOptimization": {
"maxHoldingRegistersPerRequest": 125,
"maxHoldingRegistersPerWriteRequest": 123,
"maxInputRegistersPerRequest": 125,
"maxCoilsPerRequest": 2000,
"maxDiscreteInputsPerRequest": 2000,
"concurrentRequests": 1,
"spanGaps": True,
},
"writeRequests": {
"writeMultipleRegistersRequestAllowed": True,
"forceMultipleRegisterWritesEnabled": False,
"writeMultipleCoilsRequestAllowed": True,
},
"readRequests": {
"readMultipleRegistersRequestAllowed": True,
"readMultipleCoilsAllowed": True,
"readMultipleDiscreteInputsAllowed": True,
},
"advanced": {
"reconnectAfterConsecutiveTimeouts": True,
"reverseWordOrder": False,
"zeroBasedAddressing": False,
"maxRetryCount": 1,
},
"stringHandling": {
"reverseByteOrder": False,
"rightJustifyStrings": False,
"readRawStrings": False,
},
}
config = {
"profile": {
"type": "ModbusTcp",
},
"settings": settings,
}
kwargs = {
"moduleId": DEVICE_MODULE_ID,
"typeId": DEVICE_TYPE_ID,
"name": name,
"config": config,
"enabled": enabled,
}
# Omit to use the resource type's preferred collection (normally "core").
# Pass a deployment mode name (see system.config.getModes()) to scope the device to that mode.
if collection is not None:
kwargs["collection"] = collection
if description is not None:
kwargs["description"] = description
if addressMapCsv is not None:
kwargs["files"] = {ADDRESS_MAP_KEY: csvToAddressMap(addressMapCsv)}
return system.config.create(**kwargs)
# --- Example usage ----------------------------------------------------------------------------
# Either read an exported CSV from disk on the gateway...
# csv = system.file.readFileAsString("/path/to/modbus-config.csv")
# ...or build it inline:
csv = """10
HR,1,100,false,1,HoldingRegister,1
HRF,1,20,false,1,HoldingRegisterFloat,101
C,1,32,false,1,Coil,1
DI,1,32,false,1,DiscreteInput,1
"""
resource = createModbusTcpDevice(
name="ModbusTcpScripted",
hostname="10.0.0.50",
addressMapCsv=csv,
collection="dev", # deployment mode; use None (or system.config.CORE) for the core collection
description="Created via system.config.create",
)
print resource