forked from arcpy/AutomaticUpdatesIntoFeatureService
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UpdatePointFromExternalAPI.py
202 lines (154 loc) · 6.66 KB
/
UpdatePointFromExternalAPI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
"""
This script updates a hosted feature service in ArcGIS.com (or a local Portal) from a 3rd party API or web service.
An update is performed on the point at a given interval.
Required inputs:
+ URL to a Feature Service
+ Username / password with administrator rights for the feature service
Doc Reference: http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Update_Features/02r3000000zt000000/
Blog Reference: http://
"""
import urllib
import urllib2
import json
import sys
import time
# Credentials and feature service information
username = " "
password = " "
service = "issLocation"
# Note - the URL ends with "FeatureServer". The code below handles the /0 or /n for a given layer within the service
fsURL = "http://services1.arcgis.com/....." # Example: fsURL = "http://services1.arcgis.com/aaa123/arcgis/rest/services/issLocation/FeatureServer"
# Service URL to get updates from
ISSURL = "http://api.open-notify.org/iss-now.json"
# How long to wait before updating again
pauseTime = 300 # 300 seconds = 5minutes
class AGOLHandler(object):
"""
ArcGIS Online handler class.
-Generates and keeps tokens
-template JSON feature objects for point
"""
def __init__(self, username, password, serviceName):
self.username = username
self.password = password
self.serviceName = serviceName
self.token, self.http, self.expires= self.getToken(username, password)
def getToken(self, username, password, exp=60): # expires in 60minutes
"""Generates a token."""
referer = "http://www.arcgis.com/"
query_dict = {'username': username,
'password': password,
'referer': referer}
query_string = urllib.urlencode(query_dict)
url = "https://www.arcgis.com/sharing/rest/generateToken"
token = json.loads(urllib.urlopen(url + "?f=json", query_string).read())
if "token" not in token:
print(token['error'])
sys.exit(1)
else:
httpPrefix = "http://www.arcgis.com/sharing/rest"
if token['ssl'] is True:
httpPrefix = "https://www.arcgis.com/sharing/rest"
return token['token'], httpPrefix, token['expires']
def jsonPoint(self, X, Y, ptTime):
"""Customized JSON point object for ISS schema"""
return {
"attributes": {
"OBJECTID": 1,
"TextDate": time.strftime('%m/%d/%Y %H:%MZ', time.gmtime(ptTime)),
"Long": X,
"Lat": Y
},
"geometry": {
"x": X,
"y": Y
}
}
def send_AGOL_Request(URL, query_dict, returnType=False):
"""
Helper function which takes a URL and a dictionary and sends the request.
returnType values =
False : make sure the geometry was updated properly
"JSON" : simply return the raw response from the request, it will be parsed by the calling function
else (number) : a numeric value will be used to ensure that number of features exist in the response JSON
"""
query_string = urllib.urlencode(query_dict)
jsonResponse = urllib.urlopen(URL, urllib.urlencode(query_dict))
jsonOutput = json.loads(jsonResponse.read())
if returnType == "JSON":
return jsonOutput
if not returnType:
if "updateResults" in jsonOutput:
try:
for updateItem in jsonOutput['updateResults']:
if updateItem['success'] is True:
print("request submitted successfully")
except:
print("Error: {0}".format(jsonOutput))
return False
else: # Check that the proper number of features exist in a layer
if len(jsonOutput['features']) != returnType:
print("FS layer needs seed values")
return False
return True
def fillEmptyGeo(con, fsURL):
"""
This function queries the service layer end points to ensure there is geometry as the
script does an update on existing geometry.
If there are no features, a dummy point is entered.
"""
ptURL = fsURL + "/0/query"
query_dict = {
"f": "json",
"where": "1=1",
"token": con.token
}
# Check 1 point exists in the point layer (0), if not, add a value
if (send_AGOL_Request(ptURL, query_dict, 1)) is False:
ptGeoURL = fsURL + "/0/addFeatures"
ptData = {
"features": con.jsonPoint(0, 0, 1000000000),
"f": "json",
"token": con.token
}
if send_AGOL_Request(ptGeoURL, ptData):
print("Inserted dummy point")
return
def updatePoint(con, ptURL, X, Y, ptTime):
"""Use a URL and X/Y values to update an existing point."""
try:
# Always updates point #1.
submitData = {
"features": con.jsonPoint(X, Y, ptTime),
"f": "json",
"token": con.token
}
jUpdate = send_AGOL_Request(ptURL, submitData)
except:
print("couldn't update point")
return
if __name__ == "__main__":
# Initialize the AGOLHandler for token and feature service JSON templates
con = AGOLHandler(username, password, service)
try:
# Check the Feature Service for the required layer and they have at least 1 point
# This call can be removed if you're certain the layer exists with a point
fillEmptyGeo(con, fsURL)
# Loop indefinitely
while True:
# Get the current ISS location and read into memory
req = urllib2.Request(ISSURL)
response = urllib2.urlopen(req)
issPoint = json.loads(response.read())
Y = issPoint['iss_position']['latitude']
X = issPoint['iss_position']['longitude']
ptTime = issPoint['timestamp']
if ((con.expires / 1000) - 61) < int(time.time()): # 60secs before token expires, get a new one
con.getToken(username, password)
# Update IIS location
updatePoint(con, fsURL + "/0/updateFeatures", X, Y, ptTime)
time.sleep(pauseTime)
# Generic exception handling: simple message is printed to the screen so the script continues to run.
# Additionally, an email or other action could be implemented below.
except Exception as e:
print("ERROR caught: {0}".format(e))