本文介紹:
Azure Function和SignalR Service 向 Web 前端推送IoT 報警信息 (C#)
視頻介紹:
將物聯網報警數據推送到web前端
圖文介紹:
注意,本文在 《實現Azure Function 通過IoT Hub Trigger將遙測消息寫入SQL數據庫(C#)》的基礎上繼續進行。
本文參照案例:https://docs.microsoft.com/zh-cn/azure/azure-signalr/signalr-quickstart-azure-functions-csharp
本文使用的示例代碼:https://github.com/Azure-Samples/signalr-service-quickstart-serverless-chat
創建SignalR Service:
填寫信息,完成創建:
找到SignalR 連接字符串:
修改上一講的示例代碼如下:
using IoTHubTrigger = Microsoft.Azure.WebJobs.EventHubTriggerAttribute;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.EventHubs;
using System.Text;
using System.Net.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Data;
using System.Data.SqlClient;
using System;
using Newtonsoft.Json;
using System.Net;
using System.IO;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
namespace Company.Function
{
public static class iothubtriggertodb
{
private static HttpClient client = new HttpClient();
[FunctionName("iothubtriggertodb")]
public static void Run(
[IoTHubTrigger("messages/events", Connection = "IotHubEventHubString")]EventData message,
[SignalR(HubName = "chat")] IAsyncCollector<SignalRMessage> signalRMessages,
ILogger log)
{
log.LogInformation($"C# IoT Hub trigger function processed a message: {Encoding.UTF8.GetString(message.Body.Array)}");
var deviceid=message.SystemProperties["iothub-connection-device-id"].ToString();
var dbstring=System.Environment.GetEnvironmentVariable("SQLConn");
Telemetry tmsg = JsonConvert.DeserializeObject<Telemetry>(Encoding.UTF8.GetString(message.Body.Array));
tmsg.funcsavedt = DateTime.Now;
tmsg.deviceid = deviceid;
try
{
//blow code are using to save data to sql db
using (SqlConnection con = new SqlConnection(dbstring))
{
con.Open();
if (con.State == ConnectionState.Open)
{
string strCmd = $"insert into dbo.Telemetry(temperature,humidity,funcsavedt,deviceid) values ({tmsg.temperature},{tmsg.humidity},'{System.DateTime.Now}','{deviceid}' )";
SqlCommand sqlcmd = new SqlCommand(strCmd, con);
int n = sqlcmd.ExecuteNonQuery();
if (n > 0)
{
log.LogInformation("save to db successfully");
}
else
{
log.LogError("save to db error");
}
}
con.Close();
}
}
catch (Exception ex)
{
log.LogInformation(ex.Message);
}
// azure functions output binding, send iot data to signalr, then push to frontend web.
signalRMessages.AddAsync(
new SignalRMessage
{
// newMessage is a function, web client should handle.
Target = "newMessage",
Arguments = new[] { new { sender=$"iot hub function from cloud-{DateTime.Now}", text=$"deviceid-{deviceid.Substring(0,10)},temperature:{tmsg.temperature},humidity:{tmsg.humidity}"} }
});
}
# region these two functions just want to show your how signalr service work
[FunctionName("negotiate")]
public static SignalRConnectionInfo GetSignalRInfo(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[SignalRConnectionInfo(HubName = "chat")] SignalRConnectionInfo connectionInfo)
{
return connectionInfo;
}
[FunctionName("messages")]
public static Task SendMessage(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] object message,
[SignalR(HubName = "chat")] IAsyncCollector<SignalRMessage> signalRMessages)
{
return signalRMessages.AddAsync(
new SignalRMessage
{
Target = "newMessage",
Arguments = new[] { message }
});
}
#endregion
}
public class Telemetry
{
public string deviceid{get;set;}
public DateTime funcsavedt{get;set; }
public double temperature { get; set; }
public double humidity { get; set; }
}
}
local.setting.json:
其中,如果將HTML部署到本地,則需要將CORS中增加:http://localhost:80或者對應的端口的URL
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "{your webjob storage connection string}",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"AzureSignalRConnectionString": "{your signalr connection string}",
"SQLConn": "Data Source =XXX.database.windows.net;Initial Catalog =DBName;User Id =xxx;Password =xxx;"
},
"Host": {
"LocalHttpPort": 7071,
"CORS": "http://localhost:8080,https://azure-samples.github.io",
"CORSCredentials": true
}
}
ctrl+shift+p,將Functions 發佈,
發佈完成後,將SignalR的連接字符串配置到Functions中:
如果前端頁面採用 https://azure-samples.github.io/signalr-service-quickstart-serverless-chat/demo/chat-v2/ 的示例頁面,則需要將其添加到Functions 的CORS配置中:
將HTML頁面託管到Storage中(本步驟是可選的,也可以部署到您自己的服務器上)
創建一個Storage Account
開啓Storage Account 的靜態網站功能:
注意,其中的主終結點名稱即爲 要訪問的URL。
將示例Html頁面上傳到 Storage Account 中自動生成的$WEB 容器中:
配置Functions 的CORS:
將Storage 靜態站點的主終結點添加到CORS中,將末尾的"/"去掉,勾選 啓用Allow-control-allow-credentials
至此,配置部分完成,打開Storage Account 的主終結點,開啓IOT 設備,可以看到數據正常推送到也web頁面上:
填寫Functions 的 URL:
如下圖,可以看到遙測的溫溼度在頁面上刷新: