# Reimplementating system.device.addDevice functionality

**URL:** <https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062>\
**Category:** Module Development\
**Tags:** ignition83\
**Created:** [September 29, 2025, 3:39pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062 "2025-09-29T15:39:20Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 3:39pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/1 "2025-09-29T15:39:20Z")

</div>

Hello, while doing testing I noticed that the system.device.addDevice functionality isn’t included for “free” in the 8.3 API anymore when I call on it to add my custom device implementation. Having a look at the warning message, I’ve pieced together that my device extension point needs to implement defaultSettings, and that I need a public static final instance in my related device config. The device that gets created uses the settings in that instance, but I can’t seem to get it to use any of the device props that I feed into addDevice’s deviceProp arg. If someone could point me in the right direction I’d appreciate it, thanks.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 29, 2025, 3:45pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/2 "2025-09-29T15:45:41Z")

</div>

I'm interested in this, too. (The prior implementation depended on internal DB column names.)

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 29, 2025, 3:57pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/3 "2025-09-29T15:57:34Z")

</div>

What does your settings/config object look like, and what are the keys you are using in the `deviceProps` dictionary?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 29, 2025, 3:58pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/4 "2025-09-29T15:58:44Z")

</div>

It looks like:

1. `addDevice` internally calls into your meta and asks it for its default settings object,
2. Encodes those settings into a JsonObject.
3. Any supplied kwargs from `addDevice` are merged into that object (using `.` to delimit nested settings identifiers).
4. Those settings are then passed back to the extension point to validate
5. The device is created

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 29, 2025, 4:41pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/5 "2025-09-29T16:41:53Z")

</div>

How would an extra resource file be added? Is there callout to handle keys that aren't direct members of the config object? How do drivers that need a list of OPC Item Paths handle this?

Can I say that I'm becoming less and less enamored with java `record` types?

---

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 4:48pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/6 "2025-09-29T16:48:03Z")

</div>

Hi Kevin,

I’m calling the following in the designer:

```python
deviceProps = {
    "snmphostname":"127.0.0.2",
    "snmpport":9000
}

system.device.addDevice(deviceType="snmpv2", deviceName="mytest", deviceProps=deviceProps)

```

And this is part of what my config looks like:

```java
public record SnmpV2DeviceConfig(Connectivity connectivity, Security security, Advanced advanced) {

```

```java
public record Connectivity( @FormCategory("CONNECTIVITY") @Label("SNMP host name*") @FormField(FormFieldType.TEXT) @DefaultValue("localhost") @Required String snmphostname, @FormCategory("CONNECTIVITY") @Label("SNMP port*") @FormField(FormFieldType.NUMBER) @DefaultValue("161") @Required int snmpport){} }

```

@paul-griffith It looks like step 3 is what I was missing. The props should have been:

```python
deviceProps = {
    "connectivity.snmphostname":"127.0.0.2",
    "connectivity.snmpport":9000
}

```

I was fiddling around with addDevice using a Mitsubishi device to make sure I wasn’t screwing up my Python scripting and it doesn’t appear I need to do the nesting with those properties? Is there something I’m not doing properly for our module? I’m referring to these properties: [system.device.addDevice - deviceProps Listing | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.3/appendix/scripting-functions/system-device/system-device-addDevice/system-device-addDevice-deviceProps-Listing#cominductiveautomationmitsubishitcpdevicetype)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 29, 2025, 4:51pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/7 "2025-09-29T16:51:15Z")

</div>

First party device drivers get extra handling for backwards compatibility so that you don't have to do extra nesting. For a third party, you're going to have to specify that extra depth in the keys you pass.

The real solution here is going to be our first party scripting API that gives you C/R/U/D of all config resources and overlaps `system.device.addDevice` entirely.

---

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 6:57pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/8 "2025-09-29T18:57:37Z")

</div>

Hi @Kevin.Herron @paul-griffith I have some other questions related to this. I have a couple of config fields that I have marked as FormFieldType.SECRET. Is it possible to create a device through scripting if I have these fields? I’d bet reference secret config would be possible, but what about embedded secret config?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 29, 2025, 7:03pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/9 "2025-09-29T19:03:29Z")

</div>

I don't think that's possible right now.

edit: created IGN-14421 for this. Not sure about timeline/priority.

---

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 7:16pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/10 "2025-09-29T19:16:47Z")

</div>

Thanks Kevin. I dunno if it matters on your end, but I think this would also have ramifications for the REST API portion as well.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 29, 2025, 7:19pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/11 "2025-09-29T19:19:34Z")

</div>

No, it's possible with the REST API right now.

---

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 7:34pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/12 "2025-09-29T19:34:20Z")

</div>

Do you mean if I were to pass the secret in clear text to the REST API it should work? Or do you mean passing an Embedded type JSON object? I found if I created a device through the web gui and copied the Embedded JSON object generated in the config.json file, I could pass those creds through the REST API and that second device would connect. I didn’t try that with addDevice, but I’d imagine it’d be similar?

Edit: Hm, they do not. Looks like my validate method thinks I’m passing nothing.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 29, 2025, 7:40pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/13 "2025-09-29T19:40:41Z")

</div>

You need to pass the embedded secret JSON object.

There is an endpoint at `/data/api/v1/encryption/encrypt` (see [http://localhost:8088/openapi#tag/encryption](http://localhost:8088/openapi#tag/encryption)) you can use to create embedded secrets.

The `system.device.addDevice` function has no idea what to do with either an actual SecretConfig nor a JsonObject that is an encoded SecretConfig. I think if you tried to pass it a String that happened to be encoded SecretConfig JSON it would be escaped and embedded in a JSON string value, not end up as a SecretConfig.

---

<div class="post-metadata">

**Author:** ![Eden.Mar](https://avatars.discourse-cdn.com/v4/letter/e/35a633/32.png) [@Eden.Mar](https://forum.inductiveautomation.com/u/Eden.Mar)\
**Post date:** [September 29, 2025, 7:56pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/14 "2025-09-29T19:56:53Z")

</div>

Good to know, thanks Kevin.

@paul-griffith Is there anywhere I can read up on that 1st party scripting API?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 29, 2025, 7:59pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/15 "2025-09-29T19:59:33Z")

</div>

IA is the first party, and the implication is that the little backwards compatibility hacks are private because they are part of the scripting implementation. There's nothing to read up on and it's just not available to you or any other 3rd party.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [June 15, 2026, 11:03am UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/16 "2026-06-15T11:03:28Z")

</div>

with Nightly Changelog: 8.3.8\*-b20260612

```python
IGN-15898: Merge feature/config-scripting into 8.3 branch
Added a new system.config script API to gateway scope, allowing create/read/update/delete of gateway configuration programmatically.
Also added and enhanced the system.secrets API to work with these new functions.

```

system.config.\* can be used to create devices too, or is it a bad idea ?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 15, 2026, 4:23pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/17 "2026-06-15T16:23:31Z")

</div>

Yes, that's absolutely an intended use case. Basically all the one-off configuration manipulation functions (in system.device, system.db, etc) can now be expressed in the `system.config` API, albeit more verbosely:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/3/d3ff8277fcf8ca26f428716f7fc5cc9d14fc8a01.png)

For instance, here's a (contrived) example of adding a Modbus device with some overrides, plus an address mapping:

```python
def modbus(hostname, port=502, timeout=2000):
	return {
	  "profile": {
	    "browsePath": "",
	    "type": "ModbusTcp"
	  },
	  "settings": {
	    "advanced": {
	      "maxRetryCount": 1,
	      "reconnectAfterConsecutiveTimeouts": True,
	      "reverseWordOrder": False,
	      "zeroBasedAddressing": False
	    },
	    "connectivity": {
	      "communicationTimeout": timeout,
	      "hostname": hostname,
	      "localAddress": "",
	      "port": port
	    },
	    "readRequests": {
	      "readMultipleCoilsAllowed": True,
	      "readMultipleDiscreteInputsAllowed": True,
	      "readMultipleRegistersRequestAllowed": True
	    },
	    "requestOptimization": {
	      "concurrentRequests": 1,
	      "maxCoilsPerRequest": 2000,
	      "maxDiscreteInputsPerRequest": 2000,
	      "maxHoldingRegistersPerRequest": 125,
	      "maxHoldingRegistersPerWriteRequest": 123,
	      "maxInputRegistersPerRequest": 125,
	      "spanGaps": True
	    },
	    "stringHandling": {
	      "readRawStrings": False,
	      "reverseByteOrder": False,
	      "rightJustifyStrings": False
	    },
	    "writeRequests": {
	      "forceMultipleRegisterWritesEnabled": False,
	      "writeMultipleCoilsRequestAllowed": True,
	      "writeMultipleRegistersRequestAllowed": True
	    }
	  }
	}

def createModbus():
	return system.config.create(
		moduleId="com.inductiveautomation.opcua",
		typeId="device",
		name="MyTestDevice",
		config=modbus("1.1.1.1"),
		files={
			"address-map.txt": system.file.readFileAsBytes("/Users/pgriffith/Downloads/modbus-config.csv")
		},
		description="A device created in a script",
		enabled=False,
		actor="joe.schmoe",
	)

```

For now, you always have to specify all the configuration - there's no merging with defaults.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [June 15, 2026, 6:06pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/18 "2026-06-15T18:06:59Z")

</div>

that's great 👍

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [July 8, 2026, 7:34am UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/19 "2026-07-08T07:34:34Z")

</div>

We need to create lots of devices with some **password** like this:

```python
  "settings": {

    "AuthPassphrase": {
      "data": {
        "ciphertext": "...",
        "encrypted_key": "...",
        "iv": "...",
        "protected": "...",
        "tag": "..."
      },
      "type": "Embedded"
    },
}

```

is there a way to achieve this ?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 8, 2026, 3:51pm UTC](https://forum.inductiveautomation.com/t/reimplementating-system-device-adddevice-functionality/111062/20 "2026-07-08T15:51:03Z")

</div>

Yes; the whole value shape inside the `AuthPassphrase` key matches the output of `system.secrets.createEmbeddedSecretConfig` - so if you want a fully inline secret you need to do three things:

1. Encrypt the plaintext
2. Wrap the plaintext into the embedded secret config shape
3. Pass this as the value into the `system.config` functions

e.g.

```python
cipher = system.secrets.encrypt('ignition')
passwordConfig = system.secrets.createEmbeddedSecretConfig(cipher)
system.config.create(
		moduleId='ignition',
		typeId='database-connection',
		name='mysqldb',
		description='test-from-scripting',
		config={
				'driver': 'MySQL',
				'translator': 'MYSQL',
				'connectURL': 'jdbc:mysql://192.168.152.1:3307/ignition',
				'username': 'root',
				'password': passwordConfig
		}

```

You can also use `system.secrets` to create a _referenced_ secret, retrieved from a secret provider, so you don't have to keep hardcoding passwords in 😃
