# SmartCover Ignition API

**URL:** <https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166>\
**Category:** Ignition\
**Created:** [July 31, 2023, 6:17pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166 "2023-07-31T18:17:43Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [July 31, 2023, 6:17pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/1 "2023-07-31T18:17:43Z")

</div>

Currently working on getting an API on Ignition to communicate with SmartCover - a data tracking package for manhole covers.  
(Refer to this thread ----\>[SmartCover API with Ignition - #3 by nruimveld](https://forum.inductiveautomation.com/t/smartcover-api-with-ignition/68064/3))

I see that there is Python code for an API with a token that would be applicable to Ignition. But I am not sure where or how I would insert this Python code on Ignition. Any insight? See below for code.

```auto
import requests
import csv
# variable to store the location id of interest
location_id = 'LOCATION_ID'
# variable to store the JWT token
token = 'TOKEN'
# set the authorization header
headers = {'Authorization': 'Bearer ' + token}
# set the request parameters
params = {
 'location': location_id,
 'start_time': '2020-07-01 00:00',
 'end_time': '2020-07-10 00:00',
 'data_type': '2' }
# make the GET request
response = requests.get('https://www.mysmartcover.com/api/locations/data.php',
params = params, headers = headers)
# store the response code
response_code = response.json()['response_code']
# store the data from the response
data = response.json()['data'][0]
# write the output to a CSV file
with open('output.csv', mode = 'w') as output_file:
 output_writer = csv.writer(output_file, delimiter = ',')
 output_writer.writerow(['datetime', 'level']) # write the column headers
 for row in data:
 output_writer.writerow(row)

```

In your case, importing the `requests` library will probably be unnecessary because of the built-in `system.net.httpClient`, `system.net.httpGet` and `system.net.httpPost` functions.

If you already have a token, you should be able to do something like this (off the top of my head):

```auto
client = system.net.httpClient()
url = "https://www.mysmartcover.com/api/locations/list.php"
headers = {
    "Authorization": "Bearer <YOUR_TOKEN_HERE>"
}
res = client.get(url, headers=headers)

if res.good:
    print res.json

```

---

<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 31, 2023, 7:16pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/2 "2023-07-31T19:16:23Z")

</div>

The code should translate pretty exactly:

```python
import csv
# variable to store the location id of interest
location_id = 'LOCATION_ID'
# variable to store the JWT token
token = 'TOKEN'
# set the authorization header
headers = {'Authorization': 'Bearer ' + token}
# set the request parameters
params = {
 'location': location_id,
 'start_time': '2020-07-01 00:00',
 'end_time': '2020-07-10 00:00',
 'data_type': '2' }
# make the GET request
response = system.net.httpClient().get('https://www.mysmartcover.com/api/locations/data.php', params = params, headers = headers)
# store the response code
response_code = response.json['response_code']
# store the data from the response
data = response.json['data'][0]
# write the output to a CSV file
with open('output.csv', mode = 'w') as output_file:
 output_writer = csv.writer(output_file, delimiter = ',')
 output_writer.writerow(['datetime', 'level']) # write the column headers
 for row in data:
 output_writer.writerow(row)

```

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 1, 2023, 12:15pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/3 "2023-08-01T12:15:55Z")

</div>

I should specify better; I don't quite understand where to implement this code onto Ignition. I'm unsure what setting, binding, etc. I need to put this code into.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 1, 2023, 12:18pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/4 "2023-08-01T12:18:06Z")

</div>

It depends when you want to call it. You could put it in a gateway schedule event if you want it to run on a schedule

---

<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:** [August 1, 2023, 1:33pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/5 "2023-08-01T13:33:10Z")

</div>

Do you actually want the output in a CSV file? I'd recommend a dataset tag, probably. Poll in a scheduled script as Nick recommends, build a dataset, write it to a tag. Then it's easy to pull into Vision or Perspective via a local binding.

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 21, 2023, 5:35pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/6 "2023-08-21T17:35:04Z")

</div>

Pardon my delayed reply.

I think you have a great idea. However, I am struggling with defining the 'LOCATION\_ID' variable in the Python script. There are some insights within the API documentation provided by SmartCover, however, I am having a hard time making sense of it. Any ideas to define/quantify location id within that Python script?

[25014SD REV D API Documentation.pdf](https://forum.inductiveautomation.com/uploads/short-url/ttVxyqK3lGfwBwAfjpl4Tg91lxP.pdf) (373.7 KB)

---

<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:** [August 21, 2023, 5:48pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/7 "2023-08-21T17:48:37Z")

</div>

You'll have to run their list method (manually, once) to determine the ID that corresponds to whatever unit(s) you're trying to retrieve historical data for; see page 5 where they're using `curl` (a commonly available tool to fetch from a URL via the command line).

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 22, 2023, 12:19pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/8 "2023-08-22T12:19:38Z")

</div>

I didn't think it was possible to use cURL on Windows, or within the schedule script. Maybe I am misunderstanding?  
Is it possible to rewrite it in Python and add into the existing script?

---

<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:** [August 22, 2023, 12:21pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/9 "2023-08-22T12:21:55Z")

</div>

I'm pretty sure Paul meant for you to write your own jython using the curl as an example. Use `httpClient` to do what curl is doing.

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 22, 2023, 2:18pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/10 "2023-08-22T14:18:59Z")

</div>

I see now, pardon me. I appreciate your guys' insights.

I seem to be getting an error: 'global name 'requests' is not defined'

I had assumed that the 'requests' library was already in Ignition's modules? Could I be overlooking something?

---

<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:** [August 22, 2023, 2:20pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/11 "2023-08-22T14:20:01Z")

</div>

Requests is not included in Ignition, and current versions are not compatible. Use Ignition's `httpClient`.

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 22, 2023, 2:40pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/12 "2023-08-22T14:40:34Z")

</div>

Ah! I see, that was mentioned earlier in the thread.

I've been trying to use the function in the line as below, but seem to keep getting a 'httpClient not defined' error. Is there another way I should be writing this?

```
response = httpClient.get('https://www.mysmartcover.com/api/locations/data.php', params=params, headers=headers)

```

---

<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:** [August 22, 2023, 2:43pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/13 "2023-08-22T14:43:37Z")

</div>

The full name is `system.net.httpClient()`, provided by Ignition. It is typically instantiated/configured in a project library script into a top level variable, and that variable (often `client`) is then used for the actual API requests. Take a closer look at the sample (Paul's) above.

(And you can search this forum for "system.net.httpClient" for many more examples.)

---

<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:** [August 22, 2023, 3:22pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/14 "2023-08-22T15:22:24Z")

</div>

For the task of fetching the list of locations, you can use literally any HTTP client. You could try one with a GUI like Postman, Insomnia, etc, or download cURL (it's definitely available for Windows, if not already on your system), or use one built in to a 'real' IDE like IntelliJ/PyCharm/VSCode/etc, _or_ use the script console in Ignition. Hell, you could do it from your web browser console using Javascript and the fetch API.

The point is that HTTP/REST is pretty much a base lingua franca for communication between services and it doesn't matter _what_ you have, most everything can talk to it. My read of the PDF you linked before suggests that SmartCover is doing something like this:  
Each 'user' account has X meters associated with it. Once you get your (extremely long-lived...) token, when you ask the `locations` API, it's going to give you that list of X devices. Each of those have an ID, which is probably literally the same ID SmartCover is using on their own backend, and so you have to pass that ID into any cover-specific API method you want to call.

So the actual act of fetching that list is probably not something you'll have to repeat very often (only when you buy new covers?) - so it may not be worth writing up a script if you can pull the data you want out manually with a graphical tool. The actual process of talking to the cover, absolutely should be scripted, because you're going to be repeating that often. But a 'semi-automatic' process could be totally sufficient to get you past your current roadblock.

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 22, 2023, 5:32pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/15 "2023-08-22T17:32:01Z")

</div>

Your response has done a lot to further my understanding in this project, and my understanding as a whole. I very much appreciate it.

I would like to circle back to your suggestion of putting into a dataset tag. Would would be the practice of doing so?

---

<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:** [August 22, 2023, 5:42pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/16 "2023-08-22T17:42:10Z")

</div>

Datasets are an Ignition-specific construct that are designed to hold homogenously-typed columns of data with an arbitrary number of rows, associated with an identifier for the column name. You'll notice that this is basically the same as CSV, which is good for your purposes. 🙂

So, your code sample from earlier:

> [@Justin\_Thompson](#):
>
> ```auto
> with open('output.csv', mode = 'w') as output_file:
> output_writer = csv.writer(output_file, delimiter = ',')
> output_writer.writerow(['datetime', 'level']) # write the column headers
> for row in data:
> output_writer.writerow(row)
> 
> ```

Becomes something like:

```python
headers = ["datetime", "level"]
dsData = []
for row in data:
	dsData.append([row['datetime'], row['level']])

dataset = system.dataset.toDataSet(headers, dsData)
system.tag.writeBlocking(["path/to/dataset/tag"], [dataset])

```

(Exact details will depend on the format of the data you're getting from the API, and you'll probably have to go through extra steps to parse whatever timestamp they're returning into an actual Java date object; see `system.date.parse` for one possibility.)

But that's the gist.

---

<div class="post-metadata">

**Author:** ![Justin\_Thompson](https://avatars.discourse-cdn.com/v4/letter/j/a9a28c/32.png) [@Justin\_Thompson](https://forum.inductiveautomation.com/u/Justin_Thompson)\
**Post date:** [August 24, 2023, 4:14pm UTC](https://forum.inductiveautomation.com/t/smartcover-ignition-api/77166/17 "2023-08-24T16:14:07Z")

</div>

Thanks again for your help with this task.
