1

Being a Pascal programmer with little to no clue about Python I am trying to write a small and simple Python script utilizing pyicloud https://github.com/picklepete/pyicloud/ that redirects the location data json of all devices every so and so seconds over an UDP socket with desired output as shown in the bottom. The python script should be something like:

from pyicloud import PyiCloudService
api = []
api.append(PyiCloudService('JAppleseedAppleIdEmailHere', 'password'))
api.append(PyiCloudService('SomeOtherAppleIdEmailHere', 'psadfsdfassword')) 
# more accounts here if desired...
#PeerIp = '10.0.0.5'
PeerIp = '127.0.0.1'
PeerPort = 2028

import time, threading, socket, json, struct

ContinueDevicesPostionUpdate = True

def DevicesPostionUpdate():
    if ContinueDevicesPostionUpdate:
        # print(time.ctime())
        threading.Timer(10, DevicesPostionUpdate).start()

        # Code for generating json from api.devices and api.devices[].location()
        # This is where i get all sort of errors in my shotgun programming
        MESSAGE = bytes(smsg, 'utf-8')
        sock.sendto(MESSAGE, (PeerIp, PeerPort))

sock = socket.socket(socket.AF_INET,        # Internet
                     socket.SOCK_DGRAM)     # UDP
DevicesPostionUpdate()

For example the:

for k, v in api:
    for key, value in api[k].devices.items():
        print (api[k].devices[key].location())
#results in:
Exception in thread Thread-4:
Traceback (most recent call last):
  File "C:\Python33\lib\threading.py", line 901, in _bootstrap_inner
    self.run()
  File "C:\Python33\lib\threading.py", line 1142, in run
    self.function(*self.args, **self.kwargs)
  File "test.py", line 17, in DevicesPostionUpdate
    for k, v in api:
TypeError: 'PyiCloudService' object is not iterable

Or

MESSAGE = json.dumps([dict(device=device, location=device.location()) for a in api for device in a.devices.values()]).encode()
#results in:
Traceback (most recent call last):
  File "test.py", line 23, in <module>
    DevicesPostionUpdate()
  File "test.py", line 17, in DevicesPostionUpdate
    MESSAGE = json.dumps([dict(device=device, location=device.location()) for a in api for device in a.devices.values()]).encode()
  File "C:\Python33\lib\json\__init__.py", line 236, in dumps
    return _default_encoder.encode(obj)
  File "C:\Python33\lib\json\encoder.py", line 191, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Python33\lib\json\encoder.py", line 249, in iterencode
    return _iterencode(o, 0)
  File "C:\Python33\lib\json\encoder.py", line 173, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)> is not JSON serializable

Desired output should be something like:

{
    {
        u'i9vbKRGIcLYqJnXMd1b257kUWnoyEBcEh6yM+IfmiMLh7BmOpALS+w==': <AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)>,
        {   
        u'timeStamp': 1357753796553, 
        u'locationFinished': True, 
        u'longitude': -0.14189, 
        u'positionType': u'GPS', 
        u'locationType': None, 
        u'latitude': 51.501364, 
        u'isOld': False, 
        u'horizontalAccuracy': 5.0
        }
    }
    ,
    {
    u'reGYDh9XwqNWTGIhNBuEwP1ds0F/Lg5t/fxNbI4V939hhXawByErk+HYVNSUzmWV': <AppleDevice(MacBook Air 11": Johnny Appleseed's MacBook Air)>
        {   
        u'timeStamp': 1357753796553, 
        u'locationFinished': True, 
        u'longitude': -0.14189, 
        u'positionType': u'GPS', 
        u'locationType': None, 
        u'latitude': 51.501364, 
        u'isOld': False, 
        u'horizontalAccuracy': 5.0
        }
    }
    ,
    {
    u'reGYDh9XwqNWTGIhNBuEwP1ds0F/Lg5t/fxNbI4V939hhXawByErk+HYVNSUzmWV': <AppleDevice(iPhone 4S: Some Other's iPhone)>
        {   
        u'timeStamp': 1357753796553, 
        u'locationFinished': True, 
        u'longitude': -0.14189, 
        u'positionType': u'GPS', 
        u'locationType': None, 
        u'latitude': 51.501364, 
        u'isOld': False, 
        u'horizontalAccuracy': 5.0
        }
    }
}

If you do not wish to help me here you could always earn a 30$ by presenting your solution at freelancer.com

wittrup
  • 1,535
  • 1
  • 13
  • 23

2 Answers2

2

Nothing is more fun than asking a question and ending up with the answer yourself a few hours later. Thanks for helping Totem

You are a genius J.F. Sebastian!

from pyicloud import PyiCloudService
api = []
api.append(PyiCloudService('JAppleseedAppleIdEmailHere', 'password'))
api.append(PyiCloudService('SomeOtherAppleIdEmailHere', 'psadfsdfassword'))
PeerIp = '127.0.0.1'
PeerPort = 2028
ThreadRunCount = -1
InfoEveryRunTime = 10
import time, threading, socket, json
def update_device_position():
    smsg = '{\n'
    global ThreadRunCount
    ThreadRunCount += 1
    MESSAGE = json.dumps([dict(device=str(device), location=device.location()) for a in api for device in a.devices.values()]).encode()
    DevCount = 0
    for a in api:
        for key, value in a.devices.items():
            DevCount += 1
    sock.sendto(MESSAGE, (PeerIp, PeerPort))
    tmst = time.strftime('%H:%M:%S')
    if (ThreadRunCount % InfoEveryRunTime) == 0:
        ThreadRunCount = 1
        print('[' + tmst+ '] JSON of ' + str(len(MESSAGE))  +' bytes from ' + str(DevCount) + ' devices sent to ' + PeerIp + ':' + str(PeerPort)) 
                     # Internet      # UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
stopped = threading.Event()
while not stopped.wait(10):
    update_device_position()
Community
  • 1
  • 1
wittrup
  • 1,535
  • 1
  • 13
  • 23
  • try `MESSAGE = json.dumps([dict(device=device, location=device.location()) for a in api for device in a.devices.values()]).encode()` If `device` or `.location()` are not json encodable then convert them first into types that do (e.g., `str`). – jfs Dec 08 '13 at 23:09
  • have you tried a simple while loop instead of threads: `while not stopped.wait(10): update_device_position()` where `stopped = threading.Event()` that is passed from the controlling thread. Or you could [use an event loop, to run a function repeatedly](http://stackoverflow.com/a/14040516/4279) – jfs Dec 08 '13 at 23:12
  • See updated question for result of MESSAGE = json.dumps([dict(device=device, location=device.location()) for a in api for device in a.devices.values()]).encode() How does the while not stopped.wait(10) etc etc work compared to threading.Timer(10, DevicesPostionUpdate).start() solution, i.e. what is the difference? – wittrup Dec 09 '13 at 08:22
  • Read the last sentence in my previous comment (replace s/encodable/serializable/). Each call to `Timer()` creates a new thread. `stopped.wait(10)` waits until `stopped.set()` called or 10 seconds pass. – jfs Dec 09 '13 at 11:19
  • Read. Thanks. Still can't figure out the json.dumps stuff... raise TypeError(repr(o) + " is not JSON serializable") TypeError: is not JSON serializable – wittrup Dec 09 '13 at 14:30
  • if you don't need to restore `device` later from json then just call `str(device)`. It will fix `TypeError`. Otherwise convert `device` to a dictionary: `dict(model=device.model, name=device.name)` (attributes names are just an example, run `dir(device)` to see what it has). – jfs Dec 09 '13 at 14:44
  • you could use `len(devices)` to find out how many device are sent (`message = json.dumps(devices).encode()`). Read about [string formatting](http://docs.python.org/3/library/string.html#format-string-syntax): `"{timestamp}Z JSON of {nbytes} bytes from {ndevices} devices sent to {host}:{port}".format(ndevices=len(devices), nbytes=len(message), timestamp=datetime.utcnow(), host=peer_ip, port=peer_port)` – jfs Dec 10 '13 at 08:53
0

You appear to be using python 3. The .iteritems() method for dicts no longer exists, it was replaced by .items(). Try replacing it and see if that helps.

Totem
  • 7,189
  • 5
  • 39
  • 66