Device twin Сообщенные свойства не обновляются должным образом с помощью Python SDK - PullRequest
0 голосов
/ 28 января 2019

Я разделил процесс обновления программного обеспечения на несколько этапов, таких как (загрузка, распаковка, предустановка, установка, постустановка).Я устанавливаю сообщаемые свойства на каждом этапе соответственно.Но эти свойства не обновляются в процессе установки (т. Е. Невозможно увидеть изменения в сообщаемом свойстве в двойнике устройства на портале Azure), но в конце установки я получаю ответы на обратный вызов для всех установленных «сообщенных» свойств.

Я работаю над обновлением программного обеспечения с помощью Azure IOT с использованием устройства Python SDK.Для этого я изменил образец, приведенный в SDK (т.е. файл iothub_client_sample_class.py).Я использую устройство Twin для обновления программного обеспечения.Я создал желаемое свойство для «software_version» в близнеце устройства.Как только «требуемое» свойство для «software_version» изменено, начинается процесс обновления программного обеспечения.Процесс обновления программного обеспечения выполняет различные операции, поэтому я разделил этот процесс на несколько этапов.Я отправляю «заявленные» свойства для всех этапов на IotHub.Но эти «сообщаемые» не обновляются последовательно в сообщаемом свойстве устройства-близнеца на портале Azure.

import random
import time
import sys
import iothub_client
import json
from iothub_client import IoTHubClient, IoTHubClientError,  IoTHubTransportProvider
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError, DeviceMethodReturnValue
from iothub_client_args import get_iothub_opt, OptionError

# HTTP options
# Because it can poll "after 9 seconds" polls will happen effectively
# at ~10 seconds.
# Note that for scalabilty, the default value of minimumPollingTime
# is 25 minutes. For more information, see:
# https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging
TIMEOUT = 241000
MINIMUM_POLLING_TIME = 9

# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 1000

RECEIVE_CONTEXT = 0
AVG_WIND_SPEED = 10.0
MIN_TEMPERATURE = 20.0
MIN_HUMIDITY = 60.0
MESSAGE_COUNT = 5
RECEIVED_COUNT = 0
TWIN_CONTEXT = 0
METHOD_CONTEXT = 0

# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0
BLOB_CALLBACKS = 0
TWIN_CALLBACKS = 0
SEND_REPORTED_STATE_CALLBACKS = 0
METHOD_CALLBACKS = 0

firstTime = True
hub_manager = None

PROTOCOL = IoTHubTransportProvider.MQTT
CONNECTION_STRING = "XXXXXX"

base_version = '1.0.0.000'
SUCCESS = 0
firstTime = True

def downloadImage(url):
    # Code for downloading the package from url
    return 0

def unzipPackage():
    #code for unzipping the package
    return 0

def readPackageData():
    # code reading package data
    return 0

def pre_install():
    #code for installing dependencies
    return 0

def install():
    #code for installing main package
    return 0

def post_install():
    #code for verifying installation 
    return 0


def start_software_update(url,message):
    global hub_manager
    print "Starting software update process!!!!"

    reported_state = "{\"updateStatus\":\"softwareUpdateinprogress\"}"
    hub_manager.send_reported_state(reported_state, len(reported_state), 1003)
    time.sleep(1)
    status = downloadImage(url)
    if status == SUCCESS:
        reported_state = "{\"updateStatus\":\"downloadComplete\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1004)
        print "Downlaod Phase Done!!!"
        time.sleep(1)
    else:
        print "Download Phase failed!!!!"
        return False
    status = unzipPackage()
    if status == SUCCESS:
        reported_state = "{\"updateStatus\":\"UnzipComplete\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1005)
        print "Unzip Package Done!!!"
        time.sleep(1)
    else:
        print "Unzip package failed!!!"
        return False
    status = readPackageData()
    if status == SUCCESS:
        reported_state = "{\"updateStatus\":\"ReadPackageData\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1006)
        print "Reading package json data"
        time.sleep(1)
    else:
        print "Failed Reading package!!!"
        return False
    status = pre_install()
    if status == SUCCESS:
        reported_state = "{\"updateStatus\":\"PreInstallComplete\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1007)
        time.sleep(1)
        print "pre_install state successful!!!"
    else:
        print "pre_install failed!!!!"
        return False
    status = install()
    if status == SUCCESS:   
        reported_state = "{\"updateStatus\":\"InstallComplete\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1008)
        time.sleep(1)
        print "install sucessful!!!"
    else:
        print "install failed!!!"
        return False
    status = post_install()
    if status == SUCCESS:   
        reported_state = "{\"updateStatus\":\"SoftwareUpdateComplete\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1009)
        time.sleep(1)
        print "post install sucessful!!!"
    else:
        print "post install failed!!!"
        return False
    return True


def device_twin_callback(update_state, payload, user_context):
    global TWIN_CALLBACKS
    global firstTime
    global base_version
    print ( "\nTwin callback called with:\nupdateStatus = %s\npayload = %s\ncontext = %s" % (update_state, payload, user_context) )
    TWIN_CALLBACKS += 1
    print ( "Total calls confirmed: %d\n" % TWIN_CALLBACKS )
    message = json.loads(payload)
    if not firstTime:
        if message["software_version"] != base_version:
            url = message["url"]
            status = start_software_update(url,message)
            if status:
                print "software Update Successful!!!"
            else:
                print "software Update Unsuccessful!!!"
    else:
        base_version = message["desired"]["software_version"]
        print "Set firstTime to false", base_version
        firstTime = False


def send_reported_state_callback(status_code, user_context):
    global SEND_REPORTED_STATE_CALLBACKS
    print ( "Confirmation for reported state received with:\nstatus_code = [%d]\ncontext = %s" % (status_code, user_context) )
    SEND_REPORTED_STATE_CALLBACKS += 1
    print ( "    Total calls confirmed: %d" % SEND_REPORTED_STATE_CALLBACKS )


class HubManager(object):

    def __init__(
            self,
            connection_string,
            protocol=IoTHubTransportProvider.MQTT):
        self.client_protocol = protocol
        self.client = IoTHubClient(connection_string, protocol)
        if protocol == IoTHubTransportProvider.HTTP:
            self.client.set_option("timeout", TIMEOUT)
            self.client.set_option("MinimumPollingTime", MINIMUM_POLLING_TIME)
        # set the time until a message times out
        self.client.set_option("messageTimeout", MESSAGE_TIMEOUT)
        # some embedded platforms need certificate information
        # self.set_certificates()
        self.client.set_device_twin_callback(device_twin_callback, TWIN_CONTEXT)



    def send_reported_state(self, reported_state, size, user_context):
        self.client.send_reported_state(
            reported_state, size,
            send_reported_state_callback, user_context)    

def main(connection_string, protocol):
    global hub_manager
    try:
        print ( "\nPython %s\n" % sys.version )
        print ( "IoT Hub Client for Python" )

        hub_manager = HubManager(connection_string, protocol)

        print ( "Starting the IoT Hub Python sample using protocol %s..." % hub_manager.client_protocol )
        reported_state = "{\"updateStatus\":\"waitingforupdate\"}"
        hub_manager.send_reported_state(reported_state, len(reported_state), 1002)

        while True:
            time.sleep(1)

    except IoTHubError as iothub_error:
        print ( "Unexpected error %s from IoTHub" % iothub_error )
        return
    except KeyboardInterrupt:
        print ( "IoTHubClient sample stopped" )

if __name__ == '__main__':
    try:
        (CONNECTION_STRING, PROTOCOL) = get_iothub_opt(sys.argv[1:], CONNECTION_STRING)
    except OptionError as option_error:
        print ( option_error )
        usage()
        sys.exit(1)

    main(CONNECTION_STRING, PROTOCOL)

Ожидаемый результат: свойство «сообщаемое» для каждого этапа обновления программного обеспечения должно корректно обновляться в устройстве-близнеце в лазури.portal.

Фактический результат. Свойство «указанный» для каждого этапа процесса обновления программного обеспечения не обновляется должным образом.

...