Pyicloud in place of currently nonfunction iCloud binding

I created a Python script which creates a JSON output containing all devices/attributes listed in:

sudo -u openhab /usr/local/bin/icloud --username icloud_username --llist

The output can be easily parsed with json transformation (I use jython rules).
I guess the only downside will be the required reauthentication every 2 months as mentioned in the pyicloud documentation. But I’ll see …

Script (I put it in /etc/openhab/scripts/)

from pyicloud import PyiCloudService
import subprocess

# functions
def is_int(str):
    try:
        int(str)
        return True
    except ValueError:
        return False

def is_float(str):
    try:
        float(str)
        return True
    except ValueError:
        return False

# icloud username
username = "put_your_icloud_username_here"

inputString = subprocess.check_output(r'/usr/local/bin/icloud --username {0} --llist'.format(username.rstrip()), shell=True).decode(sys.stdout.encoding).strip().split("\n")

# initialize output
outputJson = ''

# read content line by line
for lineContent in inputString :
    if '-----' in lineContent :
        # remove last comma if a new device section begins
        outputJson = outputJson.strip(',')
        # add end bracket for previous device section
        outputJson = outputJson + '},'
    elif not ' - ' in lineContent :
        # new device section does not contain " - "
        outputJson = outputJson + '"' + lineContent.rstrip('\r\n') + '": {'
    elif ' - ' in lineContent :
        # add attribute name
        outputJson = outputJson + '"' + lineContent.split()[0] + '": '
        # add value without quotes when starting with {
        if lineContent.rsplit(" - ",1)[1].rstrip('\r\n').startswith('{') :
            outputJson = outputJson + lineContent.rsplit(" - ",1)[1].rstrip('\r\n') + ','
        # add value without quotes when starting with [
        elif lineContent.rsplit(" - ",1)[1].rstrip('\r\n').startswith('[') :
            outputJson = outputJson + lineContent.rsplit(" - ",1)[1].rstrip('\r\n') + ','
        # add value without quotes when value is integer
        elif is_int(lineContent.rsplit(" - ",1)[1].rstrip('\r\n')) :
            outputJson = outputJson + lineContent.rsplit(" - ",1)[1].rstrip('\r\n') + ','
        # add value without quotes when value is float
        elif is_float(lineContent.rsplit(" - ",1)[1].rstrip('\r\n')) :
            outputJson = outputJson + lineContent.rsplit(" - ",1)[1].rstrip('\r\n') + ','
        else :
            # generally remove " in attribute value to prevent JSON parsing issues
            outputJson = outputJson + '"' + lineContent.rsplit(" - ",1)[1].rstrip('\r\n').replace('"', '' ) + '",'

# clean-up outputJson
outputJson = '{' + outputJson.strip('},') + '} }'
outputJson = outputJson.replace("'", "\"")
outputJson = outputJson.replace("\"True\"", "true")
outputJson = outputJson.replace("True", "true")
outputJson = outputJson.replace("\"False\"", "false")
outputJson = outputJson.replace("False", "false")
outputJson = outputJson.replace(" None, ", " \"None\", ")

# print out result
print(outputJson)

Jython rule (I run it every 5 minutes):

"""
pyicloud control

Authorize once after reboot:
sudo -u openhab /usr/local/bin/icloud --username your_icloud_username
"""
from core.rules import rule
from core.triggers import when
from core.log import logging, LOG_PREFIX
from core import osgi
import sys

from core.actions import ScriptExecution
from core.actions import Transformation
import json

#pyicloud
from core.actions import Exec
from java.time import Duration
import math

log = logging.getLogger("org.eclipse.smarthome.model.script.pyicloud")

@rule("Pyicloud updater", description="updates the iCloud devices", tags=["pyicloud"])
@when("Time cron 5 1/5 * * * ?")
def pyicloudUpdater(event):
    #log.warn("Rule: Pyicloud updater started.")

    output = Exec.executeCommandLine(Duration.ofSeconds(15), "python3", "/etc/openhab/scripts/icloud.py")

    ##################
    # iPhone
    ##################
    #log.warn("iPhone")
    batteryLevel = Transformation.transform("JSONPATH","$.iPhone.batteryLevel",output)
    #log.warn("batteryLevel=" + batteryLevel)
    deviceStatus = Transformation.transform("JSONPATH","$.iPhone.deviceStatus",output)
    #log.warn("deviceStatus=" + deviceStatus)
    timeStamp = Transformation.transform("JSONPATH","$.iPhone.location.timeStamp",output)
    #log.warn("timeStamp=" + timeStamp)
    latitude = Transformation.transform("JSONPATH","$.iPhone.location.latitude",output)
    #log.warn("latitude=" + latitude)
    longitude = Transformation.transform("JSONPATH","$.iPhone.location.longitude",output)
    #log.warn("longitude=" + longitude)
    latitudeAcc = Transformation.transform("JSONPATH","$.iPhone.location.horizontalAccuracy",output)
    #log.warn("latitudeAcc=" + latitudeAcc)
    longitudeAcc = Transformation.transform("JSONPATH","$.iPhone.location.verticalAccuracy",output)
    #log.warn("longitudeAcc=" + longitudeAcc)
    batteryStatus = Transformation.transform("JSONPATH","$.iPhone.batteryStatus",output)
    #log.warn("batteryStatus=" + batteryStatus)

    # update OH items
    if deviceStatus.startswith("20") :
        #log.warn("OK")
        try:
            accuracy = float(math.sqrt((float(latitudeAcc)*float(latitudeAcc)) + (float(longitudeAcc) * float(longitudeAcc))))
        except:
            accuracy = 0.0
        events.postUpdate("iPhone_BatteryLevel",str(int(float(batteryLevel)*100)))
        events.postUpdate("iPhone_Location",str(latitude + ", " + longitude + ", 0.0"))
        events.postUpdate("iPhone_LocationLast",str(timeStamp))
        events.postUpdate("iPhone_LocationAccuracy",str(accuracy))
        events.postUpdate("iPhone_BatteryStatus",str(batteryStatus))
    else :
        events.postUpdate("iPhone_BatteryStatus","Unknown")

... add additional devices the same way here ...