Home  >  Support  >  Support Forum  >  How do I retrieve a file from the Device Cloud with a Digi Python script?
Notice! We've recently migrated to using a new forum, we hope you enjoy it. If you are an existing member and this is your first time visiting our new forum, please reset your password to be able to sign in.
Welcome to Digi Forum, where you can ask questions and receive answers from other members of the community.

How do I retrieve a file from the Device Cloud with a Digi Python script?

0 votes
How do I retrieve a file from the Device Cloud with a Digi Python script?

All the examples I have seen only send files out to the Device Cloud.

I know this is possible with an http call. Is there a better way to do this natively on a digi device?
asked Jan 20 in Digi TransPort by radix07 New to the Community (22 points)

Please log in or register to answer this question.

2 Answers

+1 vote
 
Best answer
Hello

The following is a python script that I wrote and use for training. It requests a file from the cloud. It then uses DOM to "pick the file apart" The second part might be more than you need. But hopefully this will give you a start.

I don't know how to attach a file so (unfortunately) I am just dumping the python into the response.

The file name was request_furnace_data_file.py as it was part of an application. You can call it anything you want. The parameters are username, password, device id (the FULL device id) , file name. So it will look for a file associated with a device.


# ***************************************************************************
# Copyright (c) 1996-2014 Digi International Inc.,
# All rights not expressly granted are reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
#
# ***************************************************************************
#
# Usage: request_furnace_data_file.py <username> <password> <deviceid> <file_name>
#

import httplib
import base64
import sys
from xml.dom.minidom import parseString
from xml.dom.minidom import Node
import os
import re
from time import sleep, ctime

def Usage():
print 'Usage: request_furnace_data_file.py <username> <password> <deviceid> <file_name>\n'

#
# function handleChildren
# purpose walk an XML tree structure and extract all data from between tags
# print out tag name and data
# This does the lion's share of the work
#
def handleChildren(theDOMObject):
# create a list of all children of the present node
theChildList = theDOMObject.childNodes
# print out what type of node we are looking at
#translateNodeType(theDOMObject.nodeType)
# element nodes will have a text node child. That is the guy with the actual data that we are looking for
if theDOMObject.nodeType == Node.ELEMENT_NODE:
print 'Element node ' + theDOMObject.nodeName
# for each child node look for text non-empty text nodes to print out
for aChildFromThisList in theChildList:
# An element node can have text nodes with no data. They have a carriage return as the text
# lets weed them out, otherwise could be valid text or attribute
# strip will remove all white space, carriage returns and line feeds included. Only print out
# text nodes that have something after being stripped
if aChildFromThisList.nodeType == Node.TEXT_NODE and len(aChildFromThisList.nodeValue.strip()) > 0:
# when we actually print out the data, do not include all of the crud
print 'Value ' + aChildFromThisList.nodeValue.strip()

# if this node has no children and no siblings then there is nothing left to do
if len(theChildList) == 0 and theDOMObject.nextSibling == None:
return
# now we nood to look for all children of this node and process them
for theChildNode in theChildList:
if theChildNode.nodeType == Node.ELEMENT_NODE:
# for now we will not worry about attributes
if theChildNode.hasAttributes() == True:
handleAttributes(theChildNode)
#print "would have handled attributes"
# iterate through the children of our present node
thisNodeHasChildren = theChildNode.hasChildNodes()
# only process if this child has children
if thisNodeHasChildren == True:
numChildren = len(theChildNode.childNodes)
tempChildren = theChildNode.childNodes
# look for element nodes that we will handle recursively
if theChildNode.nodeType == Node.ELEMENT_NODE:
handleChildren(theChildNode)

# Function: parseTheFileData
# Purpose: Take file contents from data retrieved from the cloud
# and parse it
# Inputs: the raw file dtaa. Probably in XML format
# Output: None
#
def parseTheFileData(theFileData, theTag):
print ' in parseTheFileData, we are looking starting at ' + theTag
print theFileData
# first step, turn XML file into a tree structure
myXMLDom = parseString(theFileData)
# isolate the query setting
memberList = []
memberList = myXMLDom.getElementsByTagName(theTag)
print "Found " + str(len(memberList)) + " " + theTag + " elements"
# for each tagName element let handleChildren perform the parsing and printing
for theNextMember in memberList:
print 'Calling handleChildren from parseTheFileData'
handleChildren(theNextMember)


#
# Function: SendMessage
# purpose: format an HTTP request to retrieve a file from the device cloud
# Inputs: a user name, a password for that user name, the device id of the device to which the file belongs
# (The user will need access to this device), the file nameof the file to be accessed
# Outputs: None
#
def SendMessage(username, password, deviceid, filename):

# create HTTP basic authentication string, this consists of
# "username:password" base64 encoded
auth = base64.encodestring("%s:%s"%(username,password))[:-1]


# to what URL to send the request with a given HTTP method
webservice = httplib.HTTP("login.etherios.com",80)
# set up a parameter list for building the URL for the request
myParams = (deviceid, filename)
# combine the parameters with the URL to make the full HTTP request string
theRequest = """/ws/FileData/~/%s/%s""" % myParams
print "theRequest holds " + theRequest
# add our HTTP request to the HTTP object
webservice.putrequest("GET", theRequest)

# add the authorization string into the HTTP header
webservice.putheader("Authorization", "Basic %s"%auth)
# tell the Device Cloud what types of data we'll accept...include xml
webservice.putheader("Accept", "text/html")
webservice.putheader("Accept", "text/plain")
webservice.putheader("Accept", "text/xml")
webservice.endheaders()

# send our request to the device cloud and wait for a response
# save the status information seperate from the file contents
# the try/except block guards against bad things happening
try:
theStatusCode, theStatusMessage, header = webservice.getreply()
# get the file contents
response_body = webservice.getfile().read()

# for yucks print out the reqponse
print (theStatusCode, theStatusMessage)
# print out the file data
print "File contents:\n"
print " "
print response_body
except urllib2.HTTPError, e:
print 'HTTP Error ' + str(e.code)
except urllib2.URLError, e:
print 'URL Error ' + str(e.reason)

if theStatusCode == 200:
# if the request was successful, parse the file contents
print 'got a file from the cloud'
parseTheFileData(response_body, "furnaceDataRecord")
else:
# if the request failed, just print a message
print 'Unable to get a file from the cloud'



def main(argv):
try:
iterationCount = 0
#process arguments
count = len(argv);
if count != 4:
Usage()
else:
SendMessage(argv[0], argv[1], argv[2], argv[3])
except KeyboardInterrupt:
print "Execution halted by user action"

if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
answered Jan 21 by dakotas_dad Veteran of the Digi Community (472 points)
selected Jan 22 by radix07
Support says this must be done via an HTTP call and the Device Cloud can not be easily accessed via the existing socket connection for this functionality. Somewhat disappointing, but this is the answer...
0 votes
Thank you that is very helpful.

I guess I am a little confused why the SDK examples to send a file use a Device Cloud library call "dc_data.send_dc_data". But there doesn't seem to be any support for other calls to do much else.

Doing everything with HTTP seems kinda weird when the device already has a persistent connection to the Device Cloud...
answered Jan 21 by radix07 New to the Community (22 points)
Are you trying to pull a file down to a PC or are you trying to have a device pull a file from the cloud to itself. The script I provided would be used to pull a file, pushed up by a device to the cloud, from the cloud. If you are looking to have a device pull down a file, then maybe there is another method for doing so.
I would like to pull a file from the Device Cloud to a WR21. Your method would probably work, but I don't think it's the best way.
Contact a Digi expert and get started today! CONTACT US
...