# Updating Limble Asset Information through Ignition

**URL:** <https://forum.inductiveautomation.com/t/updating-limble-asset-information-through-ignition/111559>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [October 17, 2025, 3:43pm UTC](https://forum.inductiveautomation.com/t/updating-limble-asset-information-through-ignition/111559 "2025-10-17T15:43:51Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![NP209](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/np209/32/80704_2.png) [@NP209](https://forum.inductiveautomation.com/u/NP209)\
**Post date:** [October 17, 2025, 3:43pm UTC](https://forum.inductiveautomation.com/t/updating-limble-asset-information-through-ignition/111559/1 "2025-10-17T15:43:51Z")

</div>

Hi everyone,

I wanted to share a method for updating asset fields in Limble CMMS directly from Ignition using their REST API. This approach can be really useful if you’re tracking runtime hours, maintenance counters, or any other custom fields and want to automate updates from your Ignition system.

If you have a better way of doing this, let me know. I’m still pretty new to all this, and I’m always looking for good feedback.

**Key points:**

1. **Authentication**  
Limble uses **HTTP Basic Authentication** for API requests. You’ll need a `client_id` and `client_secret`, which you get when registering your application with Limble. These credentials should ideally be stored **outside your script** (like in environment variables) for security, and then Base64-encoded to form the Authorization header.

2. **Identifying the field to update**  
Every field in Limble has a unique `valueID`. You’ll need this ID to target the correct field when sending an update request. You can usually find it via the Limble UI or API.

3. **Preparing your data**  
The API expects a JSON payload. For example, if you want to update a runtime counter, your payload will include the new value for that field.

4. **Constructing the API request**  
The endpoint to update a field typically looks like this:

5. **Error handling**  
Always wrap your request in a try/except block to catch any connection issues, authentication errors, or invalid requests. Logging the response or error message helps debug when something doesn’t update as expected.

Here is the script we are now using on a handful of machines for various tags. I have this setup on any tag where the value changes. This way it updates when the tag does.

```python
import system.util
import system.net
import base64
import json

AutoUpdate = system.tag.readBlocking("PlaceTagPathHere")[0].value

# ================================
# Limble API credentials
# ================================
# These credentials are used to authenticate with the Limble CMMS API.
# client_id and client_secret are provided when you register an application
# or integration with Limble.
client_id = "add your client id here"
client_secret = "add your secret token here"

# ================================
# Encode credentials for Basic Auth
# ================================
# Limble API uses HTTP Basic Authentication. The client_id and client_secret
# are combined with a colon, then Base64-encoded to form the Authorization header.
credentials = client_id + ":" + client_secret
auth_header = "Basic " + base64.b64encode(credentials.encode()).decode()

# ================================
# Define the value ID to update
# ================================
# Each field in Limble has a unique valueID. Here, we specify the ID for 
# "Runtime Hours" (or any other field you want to update). This will be
# used in the API endpoint URL to target the correct field.
value_id = 9999 #you will want to change this value for your field

# ================================
# Construct the API endpoint URL
# ================================
# The update_url points to the specific field on a specific asset that we want
# to modify. We append the value_id to the base URL for assets/fields.
update_url = "https://api.limblecmms.com:443/v2/assets/fields/" + str(value_id) + "/"

# ================================
# Prepare the new data to update
# ================================
# The API expects a JSON payload. Here, we set the new value for the field.
update_data = {
	"value": AutoUpdate # Replace with whatever value you want to update
}

# ================================
# Set request headers
# ================================
# Content-Type specifies that we are sending JSON data.
# Authorization contains our Base64-encoded credentials.
headers = {
	"Content-Type": "application/json",
	"Authorization": auth_header
}

# ================================
# Send PATCH request to Limble API
# ================================
# Wrap in try/except to catch any errors during the HTTP request.
try:
	# Create an HTTP client using Ignition's system.net module
	client = system.net.httpClient()

	# Send a PATCH request to update the field value
	update_response = client.patch(
		url=update_url, # API endpoint for updating the field
		headers=headers, # HTTP headers including auth
		data=json.dumps(update_data) # JSON payload as a string
	)

	# Print success message and response text to Perspective console
	system.perspective.print("Updated successfully:")
	system.perspective.print(update_response.getText())

except Exception as e:
	# Print failure message and exception details if request fails
	system.perspective.print("Failed to update")
	system.perspective.print(str(e))

```

Hope this helps someone!

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [October 17, 2025, 4:06pm UTC](https://forum.inductiveautomation.com/t/updating-limble-asset-information-through-ignition/111559/2 "2025-10-17T16:06:47Z")

</div>

Looks like a decent start. I would field the following recommendations:

Put all of this into a project library script. Echoing the [user manual](https://www.docs.inductiveautomation.com/docs/8.1/appendix/scripting-functions/system-net/system-net-httpClient):

> httpClient instances are heavyweight, so they should be created sparingly and reused as much as possible. For ease of reuse, consider instantiating a new httpClient as a top-level variable in a project library script.

Don't import anything from `system`, the various system libraries are always present in their respective scopes/contexts.

Since you aren't doing anything other than making a JSON string, consider using `system.util.jsonEncode` instead of the `json` python library.

Consider also making use of a proper logger from [`system.util.getLogger`](https://www.docs.inductiveautomation.com/docs/8.1/appendix/scripting-functions/system-util/system-util-getLogger) in addition to/instead of your print statements.

---

<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:** [October 17, 2025, 4:09pm UTC](https://forum.inductiveautomation.com/t/updating-limble-asset-information-through-ignition/111559/3 "2025-10-17T16:09:58Z")

</div>

Your LLM steered you wrong and gave you a lot more code than you need; they're quite good at that.

This is less code and does the same as what you wrote, but with better error handling and usable from any scope, not just callable from Perspective. You can drop this into the project library.

```python
# ================================
# Limble API credentials
# ================================
# These credentials are used to authenticate with the Limble CMMS API.
# client_id and client_secret are provided when you register an application
# or integration with Limble.
__client_id = "add your client id here"
__client_secret = "add your secret token here"

__client = system.net.httpClient(username=__client_id, password=__client_secret)

__logger = system.util.getLogger("LimbleApi")

def updateAsset(value_id, new_value):
	update_url = "https://api.limblecmms.com:443/v2/assets/fields/{}/".format(value_id)

	update_data = {
		"value": new_value
	}

	try:
		update_response = __client.patch(
			url=update_url,
			data=update_data
		)

		__logger.infof("Updated %s successfully: %s", value_id, update_response.text)
	except Exception as e:
		__logger.errorf("Error updating %s: %s", value_id, e)
	except java.lang.Exception as ex:
		__logger.errorf("Error updating %s", value_id, ex)

```

Particular tips:

1. Never import anything from `system` - the `system` namespace is already brought in automatically.
2. Don't use Python's `json` module, use `system.util.jsonEncode`/`system.util.jsonDecode` because they're more likely to understand Ignition/Java objects than the base Python library.
3. You don't need to manually b64 encode basic auth, `system.net.httpClient` can do that for you automatically by passing a username and password in either your client construction or on an individual request.
4. Subjectively, `"someString/{}/somethingElse".format(thingToInsert)` is easier to read than `+` based concatenation.
5. You don't need to specify a `Content-Type` of `application/json` when you're passing a dictionary as the `data` parameter to an HTTP client method; it's automatically set. That plus the automatic authorization header means you don't need a `headers` dictionary at all.
6. Encapsulating the "external" interface via a function definition and moving this to the project library is better for maintainability and performance. You can also defer minimize excessive construction of `system.net.httpClient` objects, which are heavyweight.
7. You shouldn't use `system.perspective.print` for logging/informational purposes - you should use loggers.
8. Proper loggers have automatic string substitution/formatting capabilities, and can natively handle Java exceptions (which are distinct from Python exceptions in Jython, a caveat that LLMs invariably fail to account for)
