Отправка сообщения Cloud-to-Device на устройства, предоставляемые через IoT-central
Я читал документацию этого нового предложения SaaS, но я не вижу упоминания о возможности отправки сообщения на устройство, например: для включения / выключения оборудования.
https://docs.microsoft.com/en-us/azure/iot-central/tutorial-add-device
Я вижу, что есть возможность изменить настройки устройства, так как можно изменить устройство-близнец. Также я читал, что есть способ отправить "эхо" на устройство. Но они не служат моей точной цели.
Итак, есть ли способ, которым я могу отправить сообщение C2D, используя строку подключения, которая может быть построена с помощью рутины? https://docs.microsoft.com/en-us/azure/iot-central/tutorial-add-device
Я хотел бы отправить этот C2D через AzureFunction, но было бы полезно узнать, можно ли его каким-либо образом интегрировать в интерфейс IoT-Central.
Любые другие входы для достижения моих требований (включите / выключите оборудование) также будут очень полезны!
Спасибо и всего наилучшего,
3 ответа
Как я упоминал в своем комментарии, Azure IoT Central полностью контролирует внутреннюю конечную точку, обращенную к службе IoT Hub. Однако есть способ, при котором Azure IoT Central разрешает ограниченный доступ к этой конечной точке, ориентированной на службы, и использует REST API для обработки двойника устройства и вызова прямого метода на устройстве.
Ниже приведены инструкции по получению токена sas для заголовка авторизации, необходимого для вызовов REST Api:
Получите токен доступа из приложения 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, в основном вызовы с двойниками в пути 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
Пример вызова прямого метода на устройстве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 составляет 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, который недавно был выпущен для всеобщей доступности, см. Здесь. В случае изменения формата и т. Д. Все клиенты, тестировщики и т. Д., Включенные в вышеупомянутое решение, будут затронуты.
Для вашего конкретного случая использования единственный способ сделать это сегодня - это запустить рабочий процесс приложения логики с использованием его конечной точки HTTP из функций Azure. В приложении "Логика" вы можете создать рабочий процесс, используя центральный соединитель IoT Azure, который обновляет свойства и параметры устройства.
Мы работаем над API в IoT Central, которые могут освещать варианты использования, подобные вашему, так что следите за обновлениями!
Теперь для этого доступен API:
https://docs.microsoft.com/en-us/rest/api/iotcentral/devices/executecomponentcommand
Вы можете попробовать использовать Настройки, есть тип настройки, называемый "Переключить". Чтобы реализовать это, вы можете зайти в центральное приложение IoT с портала Azure. Затем:
Перейти на вкладку "Обозреватель устройств"
Выберите устройство
- Нажмите на вкладку "Настройки" для устройства
- Нажмите на кнопку "Изменить шаблон", расположенную в верхнем правом углу.
- В разделе "Библиотека" найдите и нажмите "Переключить"
- Введите настройки для функции переключения
Если вы хотите сделать это в масштабе, вы можете создать и запустить работу
В IoT Central вы можете управлять подключенными устройствами в масштабе, используя задания. Функциональность заданий позволяет выполнять массовые обновления свойств устройства, настроек и команд.