Azure 支持的 AI Freezer Monitor 是基于制造商硬件的 IoT 监视器,它使用机器学习 (ML) 来提供潜在设备故障的早期警告。本指南涵盖了构建设备、收集训练数据、设置电子邮件警报、训练自定义自动编码器机器学习模型以及将模型部署到 ESP32 开发板。
该项目旨在为低温科学冷冻机(-60 C)提供功能,目标是减少灾难性故障和保持备用冷冻机全时运行的需要。但是,请注意,该项目主要用于演示和教育目的,尚未经过广泛的测试。
这个项目大约需要一个小时才能完全完成。
下面有关于此示例的成本和架构的详细信息,但如果您只想让它立即运行,这里是开始的步骤。
1. 登录您的 Azure 帐户
2. 单击上面的Deploy to Azure链接,为该项目预配所有资源
作为替代方案,您可以使用Azure 门户中的部署自定义模板服务部署模板,并在编辑器中选择构建您自己的模板并从该存储库上传azuredeploy.json文件。
3.为项目新建资源组
4.为您的资源选择一个区域,选择一个靠近您以获得最佳性能的区域
注意:某些资源并非在所有地区都可用
5. 为所有资源提供唯一名称
注意:某些资源需要全局唯一名称
1. 部署完成后,使用左侧导航打开新功能应用程序
2.从左侧导航中选择功能
3.选择左上角的添加
4. 在窗口中选择以下选项:
开发环境:在门户中开发
模板:定时器触发器
新功能:dataSaver
您可以保留任何其他设置
5. 创建函数后,从左侧导航中选择Code + Test
6. 在run.csx中,将所有现有代码替换为:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#r "Newtonsoft.Json"
using System;
using Newtonsoft.Json;
public static void Run(string myIoTHubMessage, ICollector outputTable, ILogger log)
{
log.LogInformation($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}");
dynamic input = JsonConvert.DeserializeObject(myIoTHubMessage);
Guid guid = Guid.NewGuid();
log.LogInformation($"Message guid: {guid}");
outputTable.Add(
new outTable() {
PartitionKey = "test",
RowKey = guid.ToString(),
deviceId = input.deviceId.ToString(),
temperature = input.Temperature}
);
}
public class outTable
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string deviceId { get; set; }
public float temperature {get; set;}
}
导航到function.json并将所有现有代码替换为:
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "myIoTHubMessage",
"direction": "in",
"eventHubName": "samples-workitems",
"connection": "ai-freezer-hub_events_IOTHUB",
"consumerGroup": "$Default"
},
{
"name": "outputTable",
"direction": "out",
"type": "table",
"tableName": "tempTable",
"connection": "AzureWebJobsStorage"
}
]
}
8. 使用以下选项对异常检测器功能重复这些步骤:
开发环境:在门户中开发
模板:IoT 中心(事件中心)
新功能:异常检测器
您可以保留任何其他设置
运行.csx:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"
#r "System.Text.Json"
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage.Table;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
public static readonly string emailAlertUrl = Environment.GetEnvironmentVariable("EMAIL_ALERT_URL");
public static readonly HttpClient client1 = new HttpClient();
// Anomaly detection API secrets
public static readonly string subscriptionKey = Environment.GetEnvironmentVariable("ANOMALY_DETECTOR_KEY");
public static readonly string endpoint = Environment.GetEnvironmentVariable("ANOMALY_DETECTOR_ENDPOINT");
const string latestPointDetectionUrl = "/anomalydetector/v1.0/timeseries/last/detect";
public const string batchDetectionUrl = "/anomalydetector/v1.0/timeseries/entire/detect";
public static DateTimeOffset targetTime;
public static async Task Run(TimerInfo myTimer, CloudTable inputTable, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
// Get traget time from when to start reading the data
targetTime = DateTime.UtcNow;
targetTime = targetTime.AddHours(-6);
log.LogInformation($"Target start time is: {targetTime}");
TableQuery rangeQuery = new TableQuery().Where(
TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThan, targetTime));
// Execute the query and loop through the results
List data = new List();
foreach (DataPoint entity in
await inputTable.ExecuteQuerySegmentedAsync(rangeQuery, null))
{
data.Add(new DataPoint() {Timestamp = entity.Timestamp, temperature = entity.temperature});
}
// Sort data by Timestamp
data.Sort((dp1, dp2) => DateTimeOffset.Compare(dp1.Timestamp, dp2.Timestamp));
List formatedData = new List();
data.ForEach( delegate(DataPoint point)
{
formatedData.Add(new FormatedData() { timestamp = point.Timestamp.ToString("yyyy-MM-ddTHH:mm:00Z"), value = point.temperature});
});
var options = new JsonSerializerOptions
{
IgnoreNullValues = true,
// PropertyNamingPolicy = new LowerCaseNamingPolicy()
};
List jsonFormat = new List();
jsonFormat.Add(new JsonFormat() {series = formatedData, granularity = "minutely", customInterval = 1, period = 90, sensitivity = 85});
string dataToSend = JsonSerializer.Serialize(jsonFormat, options);
// Call anomaly detection API
var anomalies = detectAnomaliesBatch(dataToSend, log);
if (anomalies != null){
var json = JsonSerializer.Serialize(anomalies);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client1.PostAsync(emailAlertUrl, content);
log.LogInformation(response.ToString());
}
}
static async Task Request(string apiAddress, string endpoint, string subscriptionKey, string requestData)
{
using (HttpClient client = new HttpClient { BaseAddress = new Uri(apiAddress) })
{
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
var content = new StringContent(requestData, Encoding.UTF8, "application/json");
var res = await client.PostAsync(endpoint, content);
return await res.Content.ReadAsStringAsync();
}
}
static string detectAnomaliesBatch(string requestData, ILogger log)
{
log.LogInformation("Detecting anomalies as a batch");
requestData = requestData.TrimEnd(']').TrimStart('[');
//construct the request
var result = Request(
endpoint,
batchDetectionUrl,
subscriptionKey,
requestData).Result;
//deserialize the JSON object, and display it
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(result);
System.Console.WriteLine(jsonObj);
string foundAnomalies = "Anomalies detected in the following data positions: ";
if (jsonObj["code"] != null)
{
System.Console.WriteLine($"Detection failed. ErrorCode:{jsonObj["code"]}, ErrorMessage:{jsonObj["message"]}");
log.LogInformation($"Detection failed. ErrorCode:{jsonObj["code"]}, ErrorMessage:{jsonObj["message"]}");
}
else
{
// log.LogInformation(result);
//Find and display the positions of anomalies in the data set
bool[] anomalies = jsonObj["isAnomaly"].ToObject<bool[]>();
System.Console.WriteLine("\nAnomalies detected in the following data positions:");
log.LogInformation("\nAnomalies detected in the following data positions:");
for (var i = 0; i < anomalies.Length; i++)
{
if (anomalies[i])
{
System.Console.Write(i + ", ");
log.LogInformation(i + ", ");
foundAnomalies += i;
foundAnomalies += ", ";
}
}
if (anomalies.Any(item => item == true))
{
return foundAnomalies;
}
}
return null;
}
public class FormatedData
{
public string timestamp { get; set; }
public string value { get; set; }
}
public class DataPoint : TableEntity
{
[JsonPropertyName("value")]
public string temperature { get; set;}
public string timestamp { get; set; }
}
public class JsonFormat
{
public List series { get; set; }
public string granularity { get; set; }
public int customInterval { get; set; }
public int period { get; set; }
// public float maxAnomalyRatio { get; set; }
public int sensitivity { get; set; }
}
public class LowerCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) =>
name.ToLower();
}
函数.json:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"
#r "System.Text.Json"
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage.Table;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
public static readonly string emailAlertUrl = Environment.GetEnvironmentVariable("EMAIL_ALERT_URL");
public static readonly HttpClient client1 = new HttpClient();
// Anomaly detection API secrets
public static readonly string subscriptionKey = Environment.GetEnvironmentVariable("ANOMALY_DETECTOR_KEY");
public static readonly string endpoint = Environment.GetEnvironmentVariable("ANOMALY_DETECTOR_ENDPOINT");
const string latestPointDetectionUrl = "/anomalydetector/v1.0/timeseries/last/detect";
public const string batchDetectionUrl = "/anomalydetector/v1.0/timeseries/entire/detect";
public static DateTimeOffset targetTime;
public static async Task Run(TimerInfo myTimer, CloudTable inputTable, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
// Get traget time from when to start reading the data
targetTime = DateTime.UtcNow;
targetTime = targetTime.AddHours(-6);
log.LogInformation($"Target start time is: {targetTime}");
TableQuery rangeQuery = new TableQuery().Where(
TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThan, targetTime));
// Execute the query and loop through the results
List data = new List();
foreach (DataPoint entity in
await inputTable.ExecuteQuerySegmentedAsync(rangeQuery, null))
{
data.Add(new DataPoint() {Timestamp = entity.Timestamp, temperature = entity.temperature});
}
// Sort data by Timestamp
data.Sort((dp1, dp2) => DateTimeOffset.Compare(dp1.Timestamp, dp2.Timestamp));
List formatedData = new List();
data.ForEach( delegate(DataPoint point)
{
formatedData.Add(new FormatedData() { timestamp = point.Timestamp.ToString("yyyy-MM-ddTHH:mm:00Z"), value = point.temperature});
});
var options = new JsonSerializerOptions
{
IgnoreNullValues = true,
// PropertyNamingPolicy = new LowerCaseNamingPolicy()
};
List jsonFormat = new List();
jsonFormat.Add(new JsonFormat() {series = formatedData, granularity = "minutely", customInterval = 1, period = 90, sensitivity = 85});
string dataToSend = JsonSerializer.Serialize(jsonFormat, options);
// Call anomaly detection API
var anomalies = detectAnomaliesBatch(dataToSend, log);
if (anomalies != null){
var json = JsonSerializer.Serialize(anomalies);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client1.PostAsync(emailAlertUrl, content);
log.LogInformation(response.ToString());
}
}
static async Task Request(string apiAddress, string endpoint, string subscriptionKey, string requestData)
{
using (HttpClient client = new HttpClient { BaseAddress = new Uri(apiAddress) })
{
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
var content = new StringContent(requestData, Encoding.UTF8, "application/json");
var res = await client.PostAsync(endpoint, content);
return await res.Content.ReadAsStringAsync();
}
}
static string detectAnomaliesBatch(string requestData, ILogger log)
{
log.LogInformation("Detecting anomalies as a batch");
requestData = requestData.TrimEnd(']').TrimStart('[');
//construct the request
var result = Request(
endpoint,
batchDetectionUrl,
subscriptionKey,
requestData).Result;
//deserialize the JSON object, and display it
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(result);
System.Console.WriteLine(jsonObj);
string foundAnomalies = "Anomalies detected in the following data positions: ";
if (jsonObj["code"] != null)
{
System.Console.WriteLine($"Detection failed. ErrorCode:{jsonObj["code"]}, ErrorMessage:{jsonObj["message"]}");
log.LogInformation($"Detection failed. ErrorCode:{jsonObj["code"]}, ErrorMessage:{jsonObj["message"]}");
}
else
{
// log.LogInformation(result);
//Find and display the positions of anomalies in the data set
bool[] anomalies = jsonObj["isAnomaly"].ToObject<bool[]>();
System.Console.WriteLine("\nAnomalies detected in the following data positions:");
log.LogInformation("\nAnomalies detected in the following data positions:");
for (var i = 0; i < anomalies.Length; i++)
{
if (anomalies[i])
{
System.Console.Write(i + ", ");
log.LogInformation(i + ", ");
foundAnomalies += i;
foundAnomalies += ", ";
}
}
if (anomalies.Any(item => item == true))
{
return foundAnomalies;
}
}
return null;
}
public class FormatedData
{
public string timestamp { get; set; }
public string value { get; set; }
}
public class DataPoint : TableEntity
{
[JsonPropertyName("value")]
public string temperature { get; set;}
public string timestamp { get; set; }
}
public class JsonFormat
{
public List series { get; set; }
public string granularity { get; set; }
public int customInterval { get; set; }
public int period { get; set; }
// public float maxAnomalyRatio { get; set; }
public int sensitivity { get; set; }
}
public class LowerCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) =>
name.ToLower();
}
1. 部署完成后,使用左侧导航打开新创建的 Logic App
2.从左侧导航中选择逻辑应用程序设计器
3.选择+新步骤
4. 搜索您要使用的电子邮件客户端(Office 365 Outlook、Gmail 和 Outlook.com)
5. 选择发送电子邮件操作
注意:这将根据您使用的电子邮件客户端而有所不同
6. 使用您的电子邮件帐户登录
7. 自定义您的消息,此电子邮件将在任何时候检测到异常时发送。
1. 接下来,您需要获取设备的连接字符串,导航到您之前创建的 IoT 中心
2.在左侧导航中选择物联网设备
3.在页面左上角选择+新建
4.给设备一个ID
5. 按屏幕底部的保存
6.选择您创建的设备
7. 复制您将在下一节中使用的主连接字符串
1. 将螺丝端子焊接到 MCP9600 的顶部。
2. 将引脚焊接到 MCP9600 的底部。
提示:将引脚放在面包板上,以便在焊接时将它们固定到位。
3. 将 ESP32 和热电偶放大器插入面包板。
4. 按照下面的接线图,使用跳线将热电偶放大器连接到 ESP32。
5. 将热电偶连接到 MCP9600 上的螺丝端子
下图使用通用 ESP32 开发板,即将推出带有 Adafruit Huzzah32 的新图片!
1. 如果您还没有,请将此 repo 克隆到您的计算机
2.用VS Code打开AiFreezer文件夹
3.在这个文件夹中新建一个文件,命名为config.h
4. 将以下代码粘贴到config.h
const char* ssid = "" ;
const char* password = "" ;
static const char* connectionString = "" ;
5. 填写您的网络凭据
6. 从 IoT 中心粘贴连接字符串
7. 按照本 [指南] 的第一部分将 ESP32 扩展添加到 Arduino IDE。
8. 使用 Arduino 的库管理器安装下面列出的库。如果您在 [此处]之前使用过库管理器,这是一个有用的指南。
9. Adafruit MCP9600
注意:如果系统提示您为这些库安装其他依赖项,请选择全部安装
10. 在 VS Code 中打开 FreezerTempAlert.ino,打开命令面板(CTL+SHIFT+P)并输入Arduino:Change Board Type然后搜索Adafruit ESP32 Feather
11.接下来选择活动串口,打开命令面板并输入Arduino:选择串口
12. 最后将您的代码上传到您的羽毛板,打开命令面板并输入Arduino:
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !