Skip to content

Commit

Permalink
Merge pull request #24 from ks6088ts-labs/feature/issue-23_call-direc…
Browse files Browse the repository at this point in the history
…t-method

call direct method from API server
  • Loading branch information
ks6088ts authored Oct 19, 2024
2 parents 2702aef + 3dad61f commit 3d574c2
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 1 deletion.
58 changes: 58 additions & 0 deletions docs/scenarios/1_azure_iot_hub_messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,61 @@ $ poetry run python scripts/receive_direct_method.py --verbose
[receive_direct_method.py](https://github.com/Azure/azure-iot-sdk-python/blob/main/samples/async-hub-scenarios/receive_direct_method.py) is a sample code provided by the Azure IoT SDK for Python.

## Cloud

Run API server locally to provide RESTful APIs for the edge device.

```shell
$ make server
```

## Demo

### Setup

1. Run the API server. (on local, Docker, or Azure Functions etc.)

```shell
$ make server
```

2. Run the edge device script to receive direct method requests.

```shell
$ poetry run python scripts/receive_direct_method.py --verbose
```

### Send a request to the API server to call the direct method.

Go to docs url which shows Swagger UI and send a request to the API server to call the direct method.

1. Call the direct method from API server.

From the Swagger UI, call `POST /iot_hub/call_direct_method` with the following request body.

- `method_name`: The name of the direct method to call. (e.g. `capture_image_from_file`)
- `payload`: The payload to send to the direct method. (e.g. `{"filename": "./docs/assets/1_architecture.png","blob_name": "1_architecture.png"}`)

2. Check the result.

From the Swagger UI, call `GET /blob_storage` to check the uploaded file.

3. Get the uploaded file.

Call `GET /blob_storage/images/{device_name}/{file_name}` to get the uploaded file.

4. Explain the image by Azure OpenAI API.

Call `POST /ai_services/chat/completions_with_image` with the following request body.

- `prompt`: The prompt to send to the OpenAI API.
- `file`: The image file to send to the Azure OpenAI API.

### Play with Device Twin

1. Update the device twin.

- `GET /iot_hub/device_twin` to get the device twin.

2. Check the updated device twin.

- `PATCH /iot_hub/device_twin` to update the device twin.
2 changes: 2 additions & 0 deletions iot_hub.env.template
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
IOT_HUB_DEVICE_CONNECTION_STRING="HostName=CHANGE_ME.azure-devices.net;DeviceId=CHANGE_ME;SharedAccessKey=CHANGE_ME"
IOT_HUB_DEVICE_ID="CHANGE_ME"
IOT_HUB_CONNECTION_STRING="HostName=CHANGE_ME.azure-devices.net;SharedAccessKeyName=service;SharedAccessKey=CHANGE_ME"
106 changes: 105 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ azure-iot-device = "^2.14.0"
openai = "^1.51.2"
azure-storage-blob = "^12.23.1"
opencv-python-headless = "^4.10.0.84"
azure-iot-hub = "^2.6.1"

[tool.poetry.group.dev.dependencies]
pre-commit = "^4.0.1"
Expand Down
16 changes: 16 additions & 0 deletions workshop_azure_iot/internals/iot_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from logging import getLogger

from azure.iot.device.aio import IoTHubDeviceClient
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import CloudToDeviceMethod, CloudToDeviceMethodResult

from workshop_azure_iot.settings.iot_hub import Settings

Expand Down Expand Up @@ -42,3 +44,17 @@ async def patch_device_twin(self, reported_properties: dict):
# https://learn.microsoft.com/azure/iot-hub/how-to-device-twins?pivots=programming-language-python#patch-reported-device-twin-properties
await self.connect()
await self.device_client.patch_twin_reported_properties(reported_properties_patch=reported_properties)

async def call_direct_method(self, method_name: str, payload: dict):
# https://learn.microsoft.com/ja-jp/azure/iot-hub/device-management-python#create-a-device-app-with-a-direct-method
try:
registry_manager = IoTHubRegistryManager(connection_string=self.settings.iot_hub_connection_string)
deviceMethod = CloudToDeviceMethod(method_name=method_name, payload=payload)
response: CloudToDeviceMethodResult = registry_manager.invoke_device_method(
device_id=self.settings.iot_hub_device_id,
direct_method_request=deviceMethod,
)
except Exception as e:
logger.error(f"Failed to connect to IoT Hub: {e}")
return {"error": f"Failed to connect to IoT Hub: {e}"}
return response.as_dict()
14 changes: 14 additions & 0 deletions workshop_azure_iot/routers/iot_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,17 @@ async def patch_device_twin(reported_properties: dict):
status_code=status.HTTP_200_OK,
content=await client.patch_device_twin(reported_properties),
)


@router.post("/call_direct_method")
async def call_direct_method(
method_name: str,
payload: dict,
):
return JSONResponse(
status_code=status.HTTP_200_OK,
content=await client.call_direct_method(
method_name=method_name,
payload=payload,
),
)
2 changes: 2 additions & 0 deletions workshop_azure_iot/settings/iot_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@

class Settings(BaseSettings):
iot_hub_device_connection_string: str
iot_hub_connection_string: str
iot_hub_device_id: str
model_config = SettingsConfigDict(env_file="iot_hub.env")

0 comments on commit 3d574c2

Please sign in to comment.