本文介绍:
Azure Function和SignalR Service 向 Web 前端推送IoT 报警信息 (C#)
视频介绍:
图文介绍:
注意,本文在 《实现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:
如下图,可以看到遥测的温湿度在页面上刷新: