# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.

import time
import os
import sys
import asyncio
from six.moves import input
import threading
from azure.iot.device.aio import IoTHubModuleClient
from azure.iot.device import MethodResponse
import json

# Global configurations
TEMPERATURE_THRESHOLD = 25

# Global counters
RECEIVED_MESSAGES = 0
TWIN_CALLBACKS = 0

async def main():
    try:
        if not sys.version >= "3.5.3":
            raise Exception("The module requires python 3.5.3+. Current version of Python: %s" % sys.version)
        print("IoT Hub Module Client for Python")

        # The client object is used to interact with your Azure IoT hub.
        module_client = IoTHubModuleClient.create_from_edge_environment()

        # connect the client.
        await module_client.connect()

        # define behavior for receiving an input message on input1
        async def input1_listener(module_client):
            global RECEIVED_MESSAGES
            global TEMPERATURE_THRESHOLD
            while True:
                try:
                    input_message = await module_client.receive_message_on_input("input1")  # blocking call
                    message = input_message.data
                    size = len(message)
                    message_text = message.decode('utf-8')
                    print("Data: <<<%s>>> & Size=%d" % (message_text, size))
                    custom_properties = input_message.custom_properties
                    print("Properties: %s" % custom_properties)
                    RECEIVED_MESSAGES += 1
                    print("Total messages received: %d" % RECEIVED_MESSAGES)
                    data = json.loads(message_text)
                    if "machine" in data and "temperature" in data["machine"] and data["machine"]["temperature"] > TEMPERATURE_THRESHOLD:
                        custom_properties["MessageType"] = "Alert"
                        print("Machine temperature %s exceeds threshold %s" % (data["machine"]["temperature"], TEMPERATURE_THRESHOLD))
                        await module_client.send_message_to_output(input_message, "output1")
                except Exception as ex:
                    print("Unexpected error in input1_listener: %s" % ex)

        # twin_patch_listener is invoked when the module twin's desired properties are updated
        async def twin_patch_listener(module_client):
            global TWIN_CALLBACKS
            global TEMPERATURE_THRESHOLD
            while True:
                try:
                    data = await module_client.receive_twin_desired_properties_patch()  #blocking call
                    print("The data in the desired properties patch was: %s" % data)
                    TWIN_CALLBACKS += 1
                    print("Total calls confirmed: %d" % TWIN_CALLBACKS)
                    if "TemperatureThreshold" in data:
                        TEMPERATURE_THRESHOLD = data["TemperatureThreshold"]
                        reported_patch = {"TemperatureThreshold": TEMPERATURE_THRESHOLD}
                        await module_client.patch_twin_reported_properties(reported_patch)
                        print("Reported properties updated")
                except Exception as ex:
                    print("Unexpected error in twin_patch_listener: %s" % ex)

        # define behavior for module direct method
        async def direct_method_listener(module_client):
            global RECEIVED_MESSAGES
            while True:
                method_request = await module_client.receive_method_request("GetMessageCount")
                print("Method callback called with: Method Name = {method_name}, Payload = {payload}".format(
                    method_name = method_request.name,
                    payload = method_request.payload
                ))
                response_status = 200
                response_payload = {"MessageCount": RECEIVED_MESSAGES}
                method_response = MethodResponse(method_request.request_id, response_status, payload=response_payload)
                await module_client.send_method_response(method_response)

        # define behavior for halting the application
        def stdin_listener():
            while True:
                try:
                    selection = input("Press Q to quit\n")
                    if selection == "Q" or selection == "q":
                        print("Quitting...")
                        break
                except:
                    time.sleep(10)

        # Schedule task for C2D Listener
        listeners = asyncio.gather(
            input1_listener(module_client),
            twin_patch_listener(module_client),
            direct_method_listener(module_client)
        )
        print("The sample is now waiting for messages.")

        # Run the stdin listener in the event loop
        loop = asyncio.get_event_loop()
        user_finished = loop.run_in_executor(None, stdin_listener)

        # Wait for user to indicate they are done listening for messages
        await user_finished

        # Cancel listening
        listeners.cancel()

        # Finally, disconnect
        await module_client.disconnect()
    except Exception as e:
        print ( "Unexpected error %s " % e )
        raise

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

    # If using Python 3.7 or above, you can use following code instead:
    # asyncio.run(main())
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.

import time
import os
import sys
import asyncio
from six.moves import input
import threading
from azure.iot.device.aio import IoTHubModuleClient
from azure.iot.device import MethodResponse
import json

# Global configurations
TEMPERATURE_THRESHOLD = 25

# Global counters
RECEIVED_MESSAGES = 0
TWIN_CALLBACKS = 0

async def main():
    try:
        if not sys.version >= "3.5.3":
            raise Exception("The module requires python 3.5.3+. Current version of Python: %s" % sys.version)
        print("IoT Hub Module Client for Python")

        # The client object is used to interact with your Azure IoT hub.
        module_client = IoTHubModuleClient.create_from_edge_environment()

        # connect the client.
        await module_client.connect()

        # define behavior for receiving an input message on input1
        async def input1_listener(module_client):
            global RECEIVED_MESSAGES
            global TEMPERATURE_THRESHOLD
            while True:
                try:
                    input_message = await module_client.receive_message_on_input("input1")  # blocking call
                    message = input_message.data
                    size = len(message)
                    message_text = message.decode('utf-8')
                    print("Data: <<<%s>>> & Size=%d" % (message_text, size))
                    custom_properties = input_message.custom_properties
                    print("Properties: %s" % custom_properties)
                    RECEIVED_MESSAGES += 1
                    print("Total messages received: %d" % RECEIVED_MESSAGES)
                    data = json.loads(message_text)
                    if "machine" in data and "temperature" in data["machine"] and data["machine"]["temperature"] > TEMPERATURE_THRESHOLD:
                        custom_properties["MessageType"] = "Alert"
                        print("Machine temperature %s exceeds threshold %s" % (data["machine"]["temperature"], TEMPERATURE_THRESHOLD))
                        await module_client.send_message_to_output(input_message, "output1")
                except Exception as ex:
                    print("Unexpected error in input1_listener: %s" % ex)

        # twin_patch_listener is invoked when the module twin's desired properties are updated
        async def twin_patch_listener(module_client):
            global TWIN_CALLBACKS
            global TEMPERATURE_THRESHOLD
            while True:
                try:
                    data = await module_client.receive_twin_desired_properties_patch()  #blocking call
                    print("The data in the desired properties patch was: %s" % data)
                    TWIN_CALLBACKS += 1
                    print("Total calls confirmed: %d" % TWIN_CALLBACKS)
                    if "TemperatureThreshold" in data:
                        TEMPERATURE_THRESHOLD = data["TemperatureThreshold"]
                        reported_patch = {"TemperatureThreshold": TEMPERATURE_THRESHOLD}
                        await module_client.patch_twin_reported_properties(reported_patch)
                        print("Reported properties updated")
                except Exception as ex:
                    print("Unexpected error in twin_patch_listener: %s" % ex)

        # define behavior for module direct method
        async def direct_method_listener(module_client):
            global RECEIVED_MESSAGES
            while True:
                method_request = await module_client.receive_method_request("GetMessageCount")
                print("Method callback called with: Method Name = {method_name}, Payload = {payload}".format(
                    method_name = method_request.name,
                    payload = method_request.payload
                ))
                response_status = 200
                response_payload = {"MessageCount": RECEIVED_MESSAGES}
                method_response = MethodResponse(method_request.request_id, response_status, payload=response_payload)
                await module_client.send_method_response(method_response)

        # define behavior for halting the application
        def stdin_listener():
            while True:
                try:
                    selection = input("Press Q to quit\n")
                    if selection == "Q" or selection == "q":
                        print("Quitting...")
                        break
                except:
                    time.sleep(10)

        # Schedule task for C2D Listener
        listeners = asyncio.gather(
            input1_listener(module_client),
            twin_patch_listener(module_client),
            direct_method_listener(module_client)
        )
        print("The sample is now waiting for messages.")

        # Run the stdin listener in the event loop
        loop = asyncio.get_event_loop()
        user_finished = loop.run_in_executor(None, stdin_listener)

        # Wait for user to indicate they are done listening for messages
        await user_finished

        # Cancel listening
        listeners.cancel()

        # Finally, disconnect
        await module_client.disconnect()
    except Exception as e:
        print ( "Unexpected error %s " % e )
        raise

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

    # If using Python 3.7 or above, you can use following code instead:
    # asyncio.run(main())
# Copyright (c) Microsoft. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for # full license information. # Global configurations # Global counters # The client object is used to interact with your Azure IoT hub. # connect the client. # define behavior for receiving an input message on input1 # blocking call # twin_patch_listener is invoked when the module twin's desired properties are updated #blocking call # define behavior for module direct method # define behavior for halting the application # Schedule task for C2D Listener # Run the stdin listener in the event loop # Wait for user to indicate they are done listening for messages # Cancel listening # Finally, disconnect # If using Python 3.7 or above, you can use following code instead: # asyncio.run(main())