Integrating Real-Time Temperature Monitoring and Alerts in an AngularJS and ASP.NET Core Application Using SignalR
In today’s fast-paced world, real-time data processing and alert systems are critical for a wide range of applications, from environmental monitoring to industrial automation. This article delves into the practical implementation of a real-time temperature monitoring and alert system using AngularJS and ASP.NET Core with SignalR.
Overview
The goal of this project is to create a web application that continuously monitors temperature values, updates them in real-time on the client side, and generates alerts when the temperature exceeds a specified range. The system will also send email notifications for critical alerts. The stack includes AngularJS for the front end, ASP.NET Core for the back end, and SignalR for real-time communication.
Technology Stack
- AngularJS: A powerful JavaScript framework for building dynamic web applications.
- ASP.NET Core: A robust, high-performance framework for building modern web applications and APIs.
- SignalR: A library for ASP.NET that simplifies the process of adding real-time web functionality to applications.
Implementation Details
Step 1. Install SignalR Package
First, you need to install the SignalR package for ASP.NET Core. You can do this using the NuGet Package Manager or the .NET CLI.
Using NuGet Package Manager.
- Open your project in Visual Studio.
- Right-click on your project in the Solution Explorer.
- Select "Manage NuGet Packages".
- Search for Microsoft.AspNetCore.SignalR and install the package.
Using .NET CLI
Open your terminal or command prompt and navigate to your project directory, then run the following command.
dotnet add package Microsoft.AspNetCore.SignalR
Step 2. Configure SignalR in ASP.NET Core
Next, you need to configure SignalR in your ASP.NET Core application.
Configure Services
In the ConfigureServices method, add SignalR services to the dependency injection container.
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSignalR(); }
Configure Middleware
In the Configure method, set up routing for your SignalR hubs.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<TemperatureHub>("/temperatureHub");
});
}
AngularJS Front-End
The front end comprises a form where users can input minimum and maximum temperature values. The application generates a random temperature within this range at regular intervals and displays it on the web page. If the temperature exceeds the defined limits, an alert is generated, and an email notification is sent.
HTML View
<!DOCTYPE html>
<html lang="en" ng-app="temperatureApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Temperature Range</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
<link rel="stylesheet" href="~/plugins/fontawesome-free/css/all.min.css">
<link rel="stylesheet" href="~/dist/css/adminlte.min.css">
</head>
<body class="hold-transition sidebar-mini" ng-controller="TemperatureController">
<div class="wrapper">
<div class="content-wrapper" style="min-height: 319px; margin-left: 0!important; margin-right: 0!important;">
<section class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1>Temperature Form</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item active">General Form</li>
</ol>
</div>
</div>
</div>
</section>
<section class="content">
<div class="container-fluid">
<div class="row" style="display: flex; justify-content: center;">
<div class="col-md-6">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Temperature</h3>
</div>
<form>
<div class="card-body">
<div class="form-group">
<label for="minTemperature">Min-Temperature</label>
<input type="number" class="form-control" ng-model="minTemperature" id="minTemperature" placeholder="Enter minimum temperature">
</div>
<div class="form-group">
<label for="maxTemperature">Max-Temperature</label>
<input type="number" class="form-control" ng-model="maxTemperature" id="maxTemperature" placeholder="Enter maximum temperature">
</div>
<div class="form-check">
<p>Random Temperature: {{ randomTemperature }}</p>
</div>
</div>
<div class="card-footer">
<button ng-click="generateAlert()" class="btn btn-primary">Generate Alert</button>
<a href="/home/graph" target="_blank" class="btn btn-primary float-right">View Graph</a>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<script src="~/plugins/jquery/jquery.min.js"></script>
<script src="~/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="~/plugins/bs-custom-file-input/bs-custom-file-input.min.js"></script>
<script src="~/dist/js/adminlte.min.js"></script>
<script src="~/dist/js/demo.js"></script>
<script src="~/angularjs/temperaturecontroller.js"></script>
<script>
$(function () {
bsCustomFileInput.init();
});
</script>
</body>
</html>
AngularJS Controller
angular.module('temperatureApp', [])
.controller('TemperatureController', function ($scope, $http, $interval) {
$scope.minTemperature = 18;
$scope.maxTemperature = 23;
$scope.randomTemperature = null;
$scope.generateRandomTemperature = function () {
var min = parseInt($scope.minTemperature);
var max = parseInt($scope.maxTemperature);
$scope.randomTemperature = Math.floor(Math.random() * (max - min + 1)) + min;
$scope.callApi($scope.randomTemperature);
};
$scope.callApi = function (temp) {
var apiUrl = '/api/GraphLive';
$http.post(apiUrl, { temperature: temp })
.then(function (response) {
console.log('API response:', response.data);
})
.catch(function (error) {
console.error('Error calling API:', error);
});
};
$interval($scope.generateRandomTemperature, 5000);
$scope.generateRandomTemperature();
$scope.generateAlert = function () {
var alertValue = "Temperature Is Very High";
var apiUrl = '/api/Alert';
$http.post(apiUrl, { alert: alertValue })
.then(function (response) {
console.log('API response:', response.data);
})
.catch(function (error) {
console.error('Error calling API:', error);
});
};
});
ASP.NET Core Back-End
The back end is responsible for processing temperature data, broadcasting real-time updates via SignalR, and sending email notifications when alerts are generated.
API Controller
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
namespace GraphLiveDemo1.ApiController
{
[Route("api")]
[ApiController]
public class GraphApi : ControllerBase
{
private readonly ILogger<GraphApi> _logger;
private readonly IHubContext<TemperatureHub> _hubContext;
public GraphApi(ILogger<GraphApi> logger, IHubContext<TemperatureHub> hubContext)
{
_logger = logger;
_hubContext = hubContext;
}
[HttpPost]
[Route("GraphLive")]
public async Task<IActionResult> GraphLive(TemperatureModel model)
{
await _hubContext.Clients.All.SendAsync("ReceiveTemperatures", model.Temperature);
return Ok(new { Message = "Graph data processed successfully" });
}
[HttpPost]
[Route("Alert")]
public async Task<IActionResult> Alert(AlertModel request)
{
await _hubContext.Clients.All.SendAsync("ReceiveAlert", request.Alert);
var emailResponse = SendEmail("[email protected]", request.Alert, "Temperature Alert");
return Ok(new { Message = "Processed successfully", EmailResponse = emailResponse });
}
private string SendEmail(string recipientEmail, string message, string subject)
{
try
{
SmtpClient smtpClient = new SmtpClient("smtp-relay.sendinblue.com", 587)
{
Credentials = new NetworkCredential("[email protected]", "your-smtp-password"),
EnableSsl = true
};
MailMessage mailMessage = new MailMessage
{
From = new MailAddress("[email protected]"),
Subject = subject,
Body = message,
IsBodyHtml = true
};
mailMessage.To.Add(new MailAddress(recipientEmail));
smtpClient.Send(mailMessage);
return "Email sent successfully";
}
catch (Exception ex)
{
return $"Error sending email: {ex.Message}";
}
}
public class TemperatureModel
{
public int Temperature { get; set; }
}
public class AlertModel
{
public string Alert { get; set; }
}
}
}
ASP.NET Core Startup Configuration
To configure ASP.NET Core to use SignalR and set up the necessary services, update the Startup class as follows.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace GraphLiveDemo1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<TemperatureHub>("/temperatureHub");
});
}
}
}
Conclusion
This real-time temperature monitoring and alert system demonstrates the power and flexibility of AngularJS, ASP.NET Core, and SignalR. The integration ensures that users receive up-to-the-minute temperature updates and alerts, enhancing responsiveness and reliability in critical applications.
By following the steps outlined in this article, developers can create robust, real-time web applications capable of handling dynamic data and generating timely notifications, ensuring a proactive approach to data monitoring and management.