diff --git a/Environment/Environment.sln.DotSettings b/Environment/Environment.sln.DotSettings index bb6f1fe..b3a605b 100644 --- a/Environment/Environment.sln.DotSettings +++ b/Environment/Environment.sln.DotSettings @@ -193,4 +193,5 @@ </TypePattern> </Patterns> True + True True \ No newline at end of file diff --git a/Environment/Service/Data/Database.cs b/Environment/Service/Data/Database.cs index ca3f62f..ead60b4 100644 --- a/Environment/Service/Data/Database.cs +++ b/Environment/Service/Data/Database.cs @@ -100,12 +100,23 @@ public class Database(IConfiguration configuration) return await connection.QueryFirstOrDefaultAsync(query, new { Name = deviceName }).ConfigureAwait(false); } - public async Task SetDeviceLastUpdatedAsync(string deviceName, DateTimeOffset? lastUpdated) + public async Task SetDeviceLastUpdatedAsync(string deviceName, DateTimeOffset? lastUpdated) { await using var connection = CreateConnection(); var query = ResourceReader.GetString("ChrisKaczor.HomeMonitor.Environment.Service.Data.Queries.SetDeviceLastUpdated.psql"); - await connection.ExecuteAsync(query, new { Name = deviceName, LastUpdated = lastUpdated }).ConfigureAwait(false); + var stoppedReporting = await connection.QueryFirstAsync(query, new { Name = deviceName, LastUpdated = lastUpdated }).ConfigureAwait(false); + + return stoppedReporting; + } + + public async Task SetDeviceStoppedReportingAsync(string deviceName, bool stoppedReporting) + { + await using var connection = CreateConnection(); + + var query = ResourceReader.GetString("ChrisKaczor.HomeMonitor.Environment.Service.Data.Queries.SetDeviceStoppedReporting.psql"); + + await connection.ExecuteAsync(query, new { Name = deviceName, StoppedReporting = stoppedReporting }).ConfigureAwait(false); } } \ No newline at end of file diff --git a/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql b/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql index 4743393..db0e3d8 100644 --- a/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql +++ b/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql @@ -1,11 +1,16 @@ INSERT INTO device( name, - last_updated + last_updated, + stopped_reporting ) VALUES ( @Name, - @LastUpdated + @LastUpdated, + false ) ON CONFLICT (name) DO UPDATE - SET last_updated = EXCLUDED.last_updated \ No newline at end of file + SET last_updated = EXCLUDED.last_updated, + stopped_reporting = false +RETURNING + (SELECT stopped_reporting FROM device WHERE name = @Name); \ No newline at end of file diff --git a/Environment/Service/Data/Queries/SetDeviceStoppedReporting.psql b/Environment/Service/Data/Queries/SetDeviceStoppedReporting.psql new file mode 100644 index 0000000..722a920 --- /dev/null +++ b/Environment/Service/Data/Queries/SetDeviceStoppedReporting.psql @@ -0,0 +1,6 @@ +UPDATE + device +SET + stopped_reporting = @StoppedReporting +WHERE + name = @Name; \ No newline at end of file diff --git a/Environment/Service/Data/Schema/3-Device Table - StoppedReporting.psql b/Environment/Service/Data/Schema/3-Device Table - StoppedReporting.psql new file mode 100644 index 0000000..0d95161 --- /dev/null +++ b/Environment/Service/Data/Schema/3-Device Table - StoppedReporting.psql @@ -0,0 +1,4 @@ +ALTER TABLE + device +ADD COLUMN + stopped_reporting boolean NOT NULL DEFAULT false; \ No newline at end of file diff --git a/Environment/Service/DeviceCheckService.cs b/Environment/Service/DeviceCheckService.cs index 3866ddd..82e3c09 100644 --- a/Environment/Service/DeviceCheckService.cs +++ b/Environment/Service/DeviceCheckService.cs @@ -1,26 +1,21 @@ using ChrisKaczor.HomeMonitor.Environment.Service.Data; -using RestSharp; namespace ChrisKaczor.HomeMonitor.Environment.Service; -public class DeviceCheckService(Database _database, IConfiguration _configuration) : IHostedService +public class DeviceCheckService(Database database, IConfiguration configuration, TelegramSender telegramSender) : IHostedService { private Timer? _timer; private TimeSpan _warningInterval; - private readonly string _botToken = _configuration["Telegram:BotToken"]!; - private readonly string _chatId = _configuration["Telegram:PersonalChatId"]!; - private readonly RestClient _restClient = new(); - public Task StartAsync(CancellationToken cancellationToken) { WriteLog("DeviceCheckService started"); - _warningInterval = TimeSpan.Parse(_configuration["Environment:DeviceWarningInterval"]!); + _warningInterval = TimeSpan.Parse(configuration["Environment:DeviceWarningInterval"]!); - var checkInterval = TimeSpan.Parse(_configuration["Environment:DeviceCheckInterval"]!); + var checkInterval = TimeSpan.Parse(configuration["Environment:DeviceCheckInterval"]!); - _timer = new Timer((state) => DoWork().Wait(), null, TimeSpan.Zero, checkInterval); + _timer = new Timer(_ => DoWork().Wait(cancellationToken), null, TimeSpan.Zero, checkInterval); return Task.CompletedTask; } @@ -29,7 +24,7 @@ public class DeviceCheckService(Database _database, IConfiguration _configuratio { WriteLog("Checking devices started"); - var devices = await _database.GetDevicesAsync(); + var devices = await database.GetDevicesAsync(); foreach (var device in devices) { @@ -50,11 +45,9 @@ public class DeviceCheckService(Database _database, IConfiguration _configuratio if (message.Length > 0) { - var encodedMessage = Uri.EscapeDataString(message); + await database.SetDeviceStoppedReportingAsync(device.Name, true); - var restRequest = new RestRequest($"https://api.telegram.org/bot{_botToken}/sendMessage?chat_id={_chatId}&text={encodedMessage}"); - - await _restClient.GetAsync(restRequest); + await telegramSender.SendMessageAsync(message); } } diff --git a/Environment/Service/MessageHandler.cs b/Environment/Service/MessageHandler.cs index 55a5c07..9a82be1 100644 --- a/Environment/Service/MessageHandler.cs +++ b/Environment/Service/MessageHandler.cs @@ -17,11 +17,13 @@ public class MessageHandler : IHostedService private readonly MqttFactory _mqttFactory; private readonly string _topic; private readonly HubConnection? _hubConnection; + private readonly TelegramSender _telegramSender; - public MessageHandler(IConfiguration configuration, Database database) + public MessageHandler(IConfiguration configuration, Database database, TelegramSender telegramSender) { _configuration = configuration; _database = database; + _telegramSender = telegramSender; _topic = _configuration["Mqtt:Topic"] ?? string.Empty; @@ -77,9 +79,16 @@ public class MessageHandler : IHostedService await _database.StoreMessageAsync(message); - await _database.SetDeviceLastUpdatedAsync(message.Name, message.Timestamp); + var hadStoppedReporting = await _database.SetDeviceLastUpdatedAsync(message.Name, message.Timestamp); await SendMessage(message); + + if (hadStoppedReporting) + { + var telegramMessage = $"Device now reporting: {message.Name}"; + + await _telegramSender.SendMessageAsync(telegramMessage); + } } private async Task SendMessage(DeviceMessage message) diff --git a/Environment/Service/Program.cs b/Environment/Service/Program.cs index e7ac160..9a7ecb1 100644 --- a/Environment/Service/Program.cs +++ b/Environment/Service/Program.cs @@ -19,6 +19,7 @@ public static class Program builder.Services.AddControllers(); builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); diff --git a/Environment/Service/Service.csproj b/Environment/Service/Service.csproj index 8c63f45..cce24ff 100644 --- a/Environment/Service/Service.csproj +++ b/Environment/Service/Service.csproj @@ -28,8 +28,10 @@ + + @@ -40,7 +42,7 @@ - + diff --git a/Environment/Service/TelegramSender.cs b/Environment/Service/TelegramSender.cs new file mode 100644 index 0000000..3ed48de --- /dev/null +++ b/Environment/Service/TelegramSender.cs @@ -0,0 +1,19 @@ +using RestSharp; + +namespace ChrisKaczor.HomeMonitor.Environment.Service; + +public class TelegramSender(IConfiguration configuration) +{ + private readonly string _botToken = configuration["Telegram:BotToken"]!; + private readonly string _chatId = configuration["Telegram:PersonalChatId"]!; + private readonly RestClient _restClient = new(); + + public async Task SendMessageAsync(string message) + { + var encodedMessage = Uri.EscapeDataString(message); + + var restRequest = new RestRequest($"https://api.telegram.org/bot{_botToken}/sendMessage?chat_id={_chatId}&text={encodedMessage}"); + + await _restClient.GetAsync(restRequest); + } +} \ No newline at end of file