static async Task Main(string[] args) { var mongoHost = Environment.GetEnvironmentVariable("MONGO_HOST") ?? "localhost"; var interfaceHost = Environment.GetEnvironmentVariable("INTERFACE_HOST") ?? "localhost"; //wait for mongo to be available await CheckMongoAvailibility(mongoHost); await CheckWebServerAvailibility(interfaceHost); FlurlHttp.Configure(settings => { var jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, ObjectCreationHandling = ObjectCreationHandling.Replace }; settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings); }); Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); Console.WriteLine("Starting daemon"); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; SerialThread serialThread = new SerialThread(mongoHost, interfaceHost); serialThread.PlayBeep(); WebSocketThread webSocketThread = new WebSocketThread($"ws://{interfaceHost}:3001", serialThread); ProcessingThread processingThread = new ProcessingThread(serialThread, webSocketThread, mongoHost, interfaceHost); var serialPort = Environment.GetEnvironmentVariable("SERIAL_PORT"); if (string.IsNullOrEmpty(serialPort)) { serialThread.SetPortName(); } else { serialThread.SetPortName(serialPort); } var webSocketTask = webSocketThread.Start(cancellationToken); var serialTask = serialThread.Start(cancellationToken); var processingTask = processingThread.Start(cancellationToken); Task.WaitAll(webSocketTask, serialTask, processingTask); Console.WriteLine("Daemon finished"); }
// handle messages received from websocket private async Task MessageReceived(string message, WebSocketWrapper webSocketWrapper) { if (!string.IsNullOrEmpty(message)) { var messageObject = JObject.Parse(message); if (messageObject["type"].ToString() == "ping") { // ping received as heartbeat, reply with a ping await SendPing(webSocketWrapper).ConfigureAwait(false); } else if (messageObject["type"].ToString() == "pub") { // message from one of the subscriptions, see if it is a setting if (messageObject["path"].ToString() == settingsPath) { var settings = messageObject["message"]; foreach (var key in settings.Children()) { var property = key as JProperty; if (property != null) { var handled = false; var name = property.Name; var setting = settingsToSendThrough.FirstOrDefault(s => s.SettingKey == name); if (setting != null) { object propertyValue = property.Value.ToObject(setting.SettingType); this.Settings.AddOrUpdate(name, propertyValue, (name, value) => propertyValue); if (name == "RA") { alarmThread.ResetAlarm(); handled = true; } else if (name == "MT") { alarmThread.AlarmMuted = (int)propertyValue > 0; // we are only allowed to mute for one minute if ((int)propertyValue > 0) { muteResetCancellationTokenSource.Cancel(); muteResetCancellationTokenSource = new CancellationTokenSource(); var cancellationToken = muteResetCancellationTokenSource.Token; _ = Task.Run(async() => { await Task.Delay(60000); if (!cancellationToken.IsCancellationRequested) { logger.LogInformation("Resetting the mute state to zero"); await this.apiService.SendSettingToServerAsync("MT", 0); } }, muteResetCancellationTokenSource.Token); } } else if (name == "ACTIVE" && (int)propertyValue == 1) { _ = Task.Run(() => { // ACTIVE changed to 1, play short beep logger.LogInformation("Received setting from server: {0}={1}", name, propertyValue); var bytes = setting.ToBytes(propertyValue); serialThread.WriteData(bytes, (messageId) => { logger.LogDebug("The machine should have played a beep after receiving active 1"); serialThread.PlayBeep(); alarmThread.ResetAlarm(); alarmThread.SetInactive(); return(Task.CompletedTask); }); }); handled = true; serialThread.MachineState = (int)propertyValue; } else if (name == "ACTIVE") { LastSettingReceivedAt = DateTime.Now; _ = Task.Run(() => { logger.LogInformation("Received setting from server: {0}={1}", name, propertyValue); var bytes = setting.ToBytes(propertyValue); serialThread.WriteData(bytes); alarmThread.ResetAlarm(); alarmThread.SetInactive(); }); handled = true; serialThread.MachineState = (int)propertyValue; } if (!handled && setting.SendToArduino) { LastSettingReceivedAt = DateTime.Now; _ = Task.Run(() => { logger.LogInformation("Received setting from GUI/server: {0}={1}", name, propertyValue); var bytes = setting.ToBytes(propertyValue); serialThread.WriteData(bytes, (msgId) => { logger.LogInformation("Received setting ack from machine: {0}={1}", name, propertyValue); return(Task.CompletedTask); }); }); if (setting.CausesAlarmInactivity) { alarmThread.SetInactive(); } } } // end if setting != null } // end if property != null } // end foreach } } } }
// handle messages received from websocket private async Task MessageReceived(string message, WebSocketWrapper webSocketWrapper) { if (!string.IsNullOrEmpty(message)) { var messageObject = JObject.Parse(message); if (messageObject["type"].ToString() == "ping") { // ping received as heartbeat, reply with a ping await SendPing(webSocketWrapper).ConfigureAwait(false); } else if (messageObject["type"].ToString() == "pub") { // message from one of the subscriptions, see if it is a setting if (messageObject["path"].ToString() == settingsPath) { var settings = messageObject["message"]; foreach (var key in settings.Children()) { var property = key as JProperty; if (property != null) { var name = property.Name; var propertyValue = property.Value.ToObject <float>(); this.Settings[name] = propertyValue; if (name == "RA") { alarmThread.ResetAlarm(); } else if (name == "MT") { alarmThread.AlarmMuted = propertyValue > 0.0f; // we are only allowed to mute for one minute if (propertyValue > 0.0f) { muteResetCancellationTokenSource.Cancel(); muteResetCancellationTokenSource = new CancellationTokenSource(); var cancellationToken = muteResetCancellationTokenSource.Token; _ = Task.Run(async() => { await Task.Delay(60000); if (!cancellationToken.IsCancellationRequested) { logger.LogInformation("Resetting the mute state to zero"); await this.apiService.SendSettingToServerAsync("MT", 0); } }, muteResetCancellationTokenSource.Token); } } else if (name == "ACTIVE" && propertyValue >= 0.9f && propertyValue < 1.1f) // see if float value is close to 1 { _ = Task.Run(() => { // ACTIVE changed to 1, play short beep logger.LogInformation("Received setting from server: {0}={1}", name, propertyValue); var bytes = ASCIIEncoding.ASCII.GetBytes(string.Format("{0}={1}", name, propertyValue.ToString("0.00"))); serialThread.WriteData(bytes, (messageId) => { logger.LogDebug("The machine should have played a beep after receiving active 1"); serialThread.PlayBeep(); alarmThread.ResetAlarm(); alarmThread.SetInactive(); return(Task.CompletedTask); }); }); } else if (name == "ACTIVE") { LastSettingReceivedAt = DateTime.Now; _ = Task.Run(() => { logger.LogInformation("Received setting from server: {0}={1}", name, propertyValue); var bytes = ASCIIEncoding.ASCII.GetBytes(string.Format("{0}={1}", name, propertyValue.ToString("0.00"))); serialThread.WriteData(bytes); alarmThread.ResetAlarm(); alarmThread.SetInactive(); }); } var setting = settingsToSendThrough.FirstOrDefault(s => s.SettingKey == name); if (setting != null) { LastSettingReceivedAt = DateTime.Now; _ = Task.Run(() => { logger.LogInformation("Received setting from server: {0}={1}", name, propertyValue); var bytes = ASCIIEncoding.ASCII.GetBytes(string.Format("{0}={1}", name, propertyValue.ToString("0.00"))); serialThread.WriteData(bytes); }); if (setting.CausesAlarmInactivity) { alarmThread.SetInactive(); } } } } } } } }