Как я уже упоминал в своем комментарии, Azure IoT Central полностью контролирует внутреннюю конечную точку, ориентированную на службу IoT Hub.Однако есть способ, при котором Azure IoT Central разрешает ограниченный доступ к этой конечной точке, ориентированной на службы, и использует REST API для обработки двойника устройства и вызова прямого метода на устройстве.
Ниже приведеныПорядок получения токена sas для заголовка авторизации, необходимого для вызовов API REST:
Получите токен доступа из приложения Azure IoT Central.
формат:
SharedAccessSignature sr=appId&sig=xxxxx&skn=myTokenName&se=1577730019340
Обратите внимание, что appId показывает идентификатор приложения вашего приложения Azure IoT Central
Вызовите запрос REST POST, чтобы получить iothubTenantSasToken.sasToken
POST https://api.azureiotcentral.com/v1-beta/applications/{appId}/diagnostics/sasTokens
Authorization:SharedAccessSignature sr=appId&sig=xxxxx&skn=myTokenName&se=1577730019340
Ответ имеет следующий формат:
{
"iothubTenantSasToken": {
"sasToken": "SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service"
},
"eventhubSasToken": {
"sasToken": "SharedAccessSignature sr=sb%3A%2F%2Fep-ns-saas-ep-15-262-xxxxxxxxxx.servicebus.windows.net%2Fep-ehub-saas-iothu-1044564-xxxxxxxxxx&sig=xxxxxx&se=1546197703&skn=service",
"entityPath": "ep-ehub-saas-iothu-1044564-xxxxxxxxxx",
"hostname": "sb://ep-ns-saas-ep-15-262-xxxxxxxxxx.servicebus.windows.net/"
},
"expiry": 1546197703
}
SasToken для наших обращающихся к сервису вызовов конечных точек:
SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
Теперь мы можем использовать некоторые API-интерфейсы REST Azure IoT Hub, в основном вызовы с twins в пути uri, например:
https://docs.microsoft.com/en-us/rest/api/iothub/service/gettwin
https://docs.microsoft.com/en-us/rest/api/iothub/service/updatetwin
https://docs.microsoft.com/en-us/rest/api/iothub/service/replacetwin
https://docs.microsoft.com/en-us/rest/api/iothub/service/invokedevicemethod
Пример вызова метода Direct на устройстве1:
POST https://saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net/twins/device1/methods?api-version=2018-06-30
Authorization:SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
body:
{
"methodName": "writeLine",
"timeoutInSeconds": 20,
"payload": {
"input1": 12345,
"input2": "HelloDevice"
}
}
Пример обновления свойства двойных тегов устройства:
PATCH https://saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net/twins/device1?api-version=2018-06-30
Authorization:SharedAccessSignature sr=saas-iothub-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azure-devices.net&sig=xxxxx&se=1546197703&skn=service
body:
{
"tags": {
"test":12345
}
}
Обратите внимание, что срок действия sasToken expiry время 60 минут.Я рекомендую кешировать объект ответа с шага 2. и обновлять в зависимости от времени истечения.
ОБНОВЛЕНИЕ:
Ниже приведены шаги по использованию токена доступа IoT Central для обработки двойников устройства и прямого метода устройства в функции azure.
Создание токена доступа в приложении IoT Central, см. Следующий фрагмент экрана:
Добавьте этот токен доступа к настройкам приложения-функции.В этом примере Имя параметра приложения используется AzureIoTCAccessToken .Обратите внимание, что этот токен доступа можно сохранить в хранилище ключей Azure, подробнее см. здесь .
Создать функцию HttpTrigger в вашем приложении функций.
Заменить run.csx следующим кодом:
#r "Newtonsoft.Json"
#r "Microsoft.Azure.WebJobs.Extensions.Http"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Text;
// reusable client proxy
static HttpClientHelper iothub = new HttpClientHelper(Environment.GetEnvironmentVariable("AzureIoTCAccessToken"));
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var atype = new { device = new { deviceId = "", properties = new JObject(), measurements = new JObject() } };
var iotcobj = JsonConvert.DeserializeAnonymousType(await req.ReadAsStringAsync(), atype);
// get deviceId, for test puspose use the device1
string deviceId = iotcobj?.device?.deviceId ?? "device1";
// get a device twins
var response = await iothub.Client.GetAsync($"/twins/{deviceId}?api-version=2018-06-30");
string jsontext = await response.Content.ReadAsStringAsync();
log.LogInformation($"DeviceTwin: {JsonConvert.DeserializeObject(jsontext)}");
// patch on desired property
var patch = JsonConvert.SerializeObject(new { properties = new { desired = new { ping = DateTime.UtcNow } } });
response = await iothub.Client.PatchAsync($"/twins/{deviceId}?api-version=2018-06-30", new StringContent(patch, Encoding.UTF8, "application/json"));
jsontext = await response.Content.ReadAsStringAsync();
log.LogInformation($"Patch: {JsonConvert.DeserializeObject(jsontext)}");
// invoke a device method
var method = new { methodName = "writeLine", timeoutInSeconds = 30, payload = new {input1 = 12345, input2 = "HelloDevice" } };
response = await iothub.Client.PostAsJsonAsync($"/twins/{deviceId}/methods?api-version=2018-06-30", method );
jsontext = await response.Content.ReadAsStringAsync();
log.LogInformation($"DirectMethod: {JsonConvert.DeserializeObject(jsontext)}");
return new OkObjectResult(jsontext);
}
class HttpClientHelper
{
HttpClient client;
string accessToken;
dynamic iothub;
long toleranceInSeconds = 60;
public HttpClientHelper(string accessToken)
{
this.accessToken = accessToken;
this.iothub = GetIoTHubTenant(accessToken);
string hostname = GetHostNameFromSaSToken(this.iothub.iothubTenantSasToken.sasToken);
client = new HttpClient() { BaseAddress = new Uri($"https://{hostname}") };
client.DefaultRequestHeaders.Add("Authorization", iothub.iothubTenantSasToken.sasToken);
}
public HttpClient Client
{
get
{
if((new DateTime(1970, 1, 1)).AddSeconds(this.iothub.expiry - toleranceInSeconds) < DateTime.UtcNow)
SetAuthorizationHeader();
return client;
}
}
private void SetAuthorizationHeader()
{
lock (client)
{
if ((new DateTime(1970, 1, 1)).AddSeconds(this.iothub.expiry - toleranceInSeconds) < DateTime.UtcNow)
{
if (client.DefaultRequestHeaders.Contains("Authorization"))
client.DefaultRequestHeaders.Remove("Authorization");
this.iothub = GetIoTHubTenant(this.accessToken);
client.DefaultRequestHeaders.Add("Authorization", this.iothub.iothubTenantSasToken.sasToken);
}
}
}
private string GetHostNameFromSaSToken(string sastoken)
{
var parts = sastoken.Replace("SharedAccessSignature", "").Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim());
return parts["sr"] ?? "";
}
private dynamic GetIoTHubTenant(string iotcAccessToken)
{
string appId = GetHostNameFromSaSToken(iotcAccessToken);
using (var hc = new HttpClient())
{
hc.DefaultRequestHeaders.Add("Authorization", accessToken);
string address = $"https://api.azureiotcentral.com/v1-beta/applications/{appId}/diagnostics/sasTokens";
var response = hc.PostAsync(address, new StringContent("{}", Encoding.UTF8, "application/json")).Result;
return JsonConvert.DeserializeAnonymousType(response.Content.ReadAsStringAsync().Result, new { iothubTenantSasToken = new { sasToken = "" }, expiry = 0L });
}
}
}
Примечание: , вышеприведенная реализация основана на сгенерированном токене доступа вашего приложения IoT Central, как будто он недавно был выпущен для всеобщей доступности, см. здесь .В случае изменения формата и т. Д. Все клиенты, тестировщики и т. Д., Включенные в вышеуказанное решение, будут затронуты.