--- /dev/null
+import requests
+from datetime import timedelta
+
+zero = timedelta(0)
+
+application = 2
+container = 3
+contentInstance = 4
+
+op_provision = ":8181/restconf/operations/onem2m:onem2m-cse-provisioning"
+op_tree = ":8181/restconf/operational/onem2m:onem2m-resource-tree"
+op_cleanup = ":8181/restconf/operations/onem2m:onem2m-cleanup-store"
+
+cse_payload = '''
+{ "input": {
+ "onem2m-primitive": [
+ {
+ "name": "CSE_ID",
+ "value": "%s"
+ },
+ {
+ "name": "CSE_TYPE",
+ "value": "IN-CSE"
+ }
+ ]
+ }
+}
+'''
+
+application_payload = '''
+{
+ any:
+ [
+ {"aei":"jb", "api":"jb", "apn":"jb2", "or":"http://hey/you" %s}
+ ]
+}
+'''
+
+_container_payload = '''
+{
+ any:
+ [
+ {
+ "cr": "jb",
+ "mni": 1,
+ "mbs": 3,
+ "or": "http://hey/you"
+ %s
+ }
+ ]
+}
+'''
+
+container_payload = '''
+{
+ any:
+ [
+ {
+ "cr": "jb",
+ "or": "http://hey/you"
+ %s
+ }
+ ]
+}
+'''
+
+contentInstance_payload = '''
+{
+ "any": [
+ {
+ "cnf": "1",
+ "or": "http://hey/you"
+ %s
+ }
+ ]
+}
+'''
+
+
+def which_payload(restype):
+ """Return a template payload for the known datatypes."""
+ if restype == application:
+ return application_payload
+ elif restype == container:
+ return container_payload
+ elif restype == contentInstance:
+ return contentInstance_payload
+ else:
+ return ""
+
+
+def find_key(response, key):
+ try:
+ val = response.json()
+ return val['any'][0][key]
+ except:
+ return None
+
+
+def name(response):
+ """Return the resource name in the response."""
+ return find_key(response, "rn")
+
+
+def resid(response):
+ """Return the resource id in the response."""
+ return find_key(response, "ri")
+
+
+def parent(response):
+ """Return the parent resource id in the response."""
+ return find_key(response, "pi")
+
+
+def content(response):
+ """Return the content the response."""
+ return find_key(response, "con")
+
+
+def restype(response):
+ """Return the resource type the response."""
+ return find_key(response, "rty")
+
+
+def status(response):
+ """Return the protocol status code in the response."""
+ try:
+ return response.status_code
+ except:
+ return None
+
+
+def headers(response):
+ """Return the protocol headers in the response."""
+ try:
+ return response.headers
+ except:
+ return None
+
+
+def error(response):
+ """Return the error string in the response."""
+ try:
+ return response.json()['error']
+ except:
+ return None
+
+
+def normalize(id):
+ if id is not None:
+ if id[0] == "/":
+ return id[1:]
+ return id
+
+
+def attr2str(attr):
+ """Convert a dictionary into a string for a protocol payload."""
+ content = ""
+ if attr is not None:
+ content = ","
+ n = len(attr)
+ c = 1
+ sep = ","
+ for i in attr:
+ if n == c:
+ sep = ""
+ n = str(attr[i])
+ if i != "con" and n.isdigit():
+ content = content + "'%s':%d%s" % (i, int(n), sep)
+ else:
+ content = content + "'%s':'%s'%s" % (i, n, sep)
+ c = c + 1
+ return content
+
+
+class connect:
+ def __init__(self, server="localhost", base='InCSE1',
+ auth=('admin', 'admin'), protocol="http"):
+ """Connect to a IoTDM server."""
+ self.s = requests.Session()
+ self.s.auth = auth
+ self.s.headers.update({'content-type': 'application/json'})
+ self.timeout = (5, 5)
+ self.payload = cse_payload % (base)
+ self.headers = {
+ # Admittedly these are "magic values" but are required
+ # and until a proper defaulting initializer is in place
+ # are hard-coded.
+ 'content-type': 'application/json',
+ 'X-M2M-Origin': '//localhost:10000',
+ 'X-M2M-RI': '12345',
+ 'X-M2M-OT': 'NOW'
+ }
+ self.server = "http://" + server
+ if base is not None:
+ self.url = self.server + op_provision
+ self.r = self.s.post(self.url,
+ data=self.payload, timeout=self.timeout)
+
+ def create(self, parent, restype, name=None, attr=None):
+ """Create resource."""
+ if parent is None:
+ return None
+ payload = which_payload(restype)
+ payload = payload % (attr2str(attr))
+ if name is None:
+ self.headers['X-M2M-NM'] = None
+ else:
+ self.headers['X-M2M-NM'] = name
+ parent = normalize(parent)
+ self.url = self.server + ":8282/%s?ty=%s&rcn=1" % (parent, restype)
+ self.r = self.s.post(self.url, payload,
+ timeout=self.timeout, headers=self.headers)
+ return self.r
+
+ def retrieve(self, id):
+ """Retrieve resource."""
+ if id is None:
+ return None
+ id = normalize(id)
+ self.url = self.server + ":8282/%s?rcn=5&drt=2" % (id)
+ self.headers['X-M2M-NM'] = None
+ self.r = self.s.get(self.url, timeout=self.timeout,
+ headers=self.headers)
+ return self.r
+
+ def update(self, id, attr=None):
+ """Update resource attr"""
+ if id is None:
+ return None
+ id = normalize(id)
+ return None
+
+ def delete(self, id):
+ """Delete the resource with the provided ID."""
+ if id is None:
+ return None
+ id = normalize(id)
+ self.url = self.server + ":8282/%s" % (id)
+ self.headers['X-M2M-NM'] = None
+ self.r = self.s.delete(self.url, timeout=self.timeout,
+ headers=self.headers)
+ return self.r
+
+ def tree(self):
+ """Get the resource tree."""
+ self.url = self.server + op_tree
+ self.r = self.s.get(self.url)
+ return self.r
+
+ def kill(self):
+ """Kill the tree."""
+ self.url = self.server + op_cleanup
+ self.r = self.s.post(self.url)
+ return self.r