private void CreateWebSocketClient() { try { Uri uri = new Uri(String.Format($"wss://{config.Hostname}/ws/connect")); cts = new CancellationTokenSource(); channel = new WebSocketClientChannel(uri, "mqtt", new WebSocketConfig(), cts.Token); channel.OnClose += Channel_OnClose; pclient = new PiraeusMqttClient(new MqttConfig(180), channel); ConnectAckCode code = pclient.ConnectAsync(clientId, "JWT", config.SecurityToken, 90).GetAwaiter().GetResult(); Console.WriteLine($"MQTT client connection code = {code}"); if (code != ConnectAckCode.ConnectionAccepted) { throw new Exception("MQTT connection failed."); } pclient.OnChannelError += Pclient_OnChannelError; pclient.SubscribeAsync(config.RtuInputPiSystem, QualityOfServiceLevelType.AtLeastOnce, RtuInput).GetAwaiter(); } catch (Exception ex) { Console.WriteLine($"Exception creating web socket client - {ex.Message}"); SetDelay(); CreateWebSocketClient(); } }
private void Channel_OnReceive(object sender, ChannelReceivedEventArgs e) { try { MbapHeader header = MbapHeader.Decode(e.Message); if (!unitId.HasValue) { unitId = header.UnitId; } if (unitId.HasValue && header.UnitId == unitId.Value) { RtuPiSystem piSystem = map.GetItem((ushort)unitId.Value); if (piSystem == null) { throw new Exception($"PI-System not found for unit id - {unitId.Value}"); } else { client.SubscribeAsync(piSystem.RtuOutputEvent, QualityOfServiceLevelType.AtLeastOnce, ReceiveOutput).GetAwaiter(); client.PublishAsync(QualityOfServiceLevelType.AtLeastOnce, piSystem.RtuInputEvent, contentType, e.Message).GetAwaiter(); } } else { throw new Exception("Unit Id missing from SCADA client message."); } } catch (Exception ex) { OnError?.Invoke(this, new AdapterErrorEventArgs(Id, ex)); } }
public async Task AddSubscriptionAsync(string piSystem, Action <string, string, byte[]> action) { if (IsConnected) { await client.SubscribeAsync(piSystem.ToLowerInvariant(), QualityOfServiceLevelType.AtMostOnce, action); logger?.LogDebug($"Web socket client subscribed to {piSystem}"); } else { logger?.LogWarning($"Web socket client is not connected and cannot subscribe to {piSystem}."); } }
public async Task SubscribeAsync(string resource, bool monitor) { string monitorUriString = null; string logUriString = null; string[] parts = resource.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 1) { //virtual rtu monitorUriString = UriGenerator.GetVirtualRtuDiagnosticsPiSystem(hostname, parts[0]); logUriString = UriGenerator.GetVirtualRtuTelemetryPiSystem(hostname, parts[0]); } else if (parts.Length == 2) { //module monitorUriString = UriGenerator.GetDeviceDiagnosticsPiSystem(hostname, parts[0], parts[1]); logUriString = UriGenerator.GetDeviceTelemetryPiSystem(hostname, parts[0], parts[1]); } DiagnosticsMessage mevent = new DiagnosticsMessage { Type = monitor ? DiagnosticsEventType.Native : DiagnosticsEventType.None }; string jsonString = JsonConvert.SerializeObject(mevent); await client.PublishAsync(QualityOfServiceLevelType.AtMostOnce, monitorUriString, "application/json", Encoding.UTF8.GetBytes(jsonString)); if (monitor) { if (!subscriptions.Contains(logUriString)) { subscriptions.Add(logUriString); await client.SubscribeAsync(logUriString, QualityOfServiceLevelType.AtMostOnce, ReceiveLog); } } else { if (subscriptions.Contains(logUriString)) { subscriptions.Remove(logUriString); await client.UnsubscribeAsync(logUriString); } } }
public async Task SendAsync(byte[] message) { if (client == null || !client.IsConnected) { logger?.LogWarning("MQTT client is not available to forward message."); return; } try { MbapHeader header = MbapHeader.Decode(message); if (map.HasItem(header.UnitId)) { if (!subscriptions.Contains(header.UnitId)) { string resource = map.GetItem(header.UnitId).RtuOutputEvent; await client.SubscribeAsync(resource, QualityOfServiceLevelType.AtMostOnce, ModbusMessageReceived); logger?.LogInformation( $"MQTT client channel subscribed {resource} with Unit ID = {header.UnitId}"); subscriptions.Add(header.UnitId); } cache.Add(GetCacheKey(header), new Tuple <ushort, byte[]>(header.TransactionId, message), 20.0); string pisystem = map.GetItem(header.UnitId).RtuInputEvent; await client.PublishAsync(QualityOfServiceLevelType.AtMostOnce, pisystem, "application/octet-stream", message); logger?.LogDebug($"VRTU published to {pisystem}"); await diag?.PublishInput(header); } else { logger?.LogWarning($"Unit Id = {header.UnitId} in Modbus message not found in RTU map."); } } catch (Exception ex) { logger?.LogError(ex, "Fault sending MQTT client channel."); } }
static async Task StartMqttClientAsync(string token) { ConnectAckCode code = await MqttConnectAsync(token); if (code != ConnectAckCode.ConnectionAccepted) { return; } string observableEvent = role == "A" ? "http://www.skunklab.io/resource-b" : "http://www.skunklab.io/resource-a"; try { await mqttClient.SubscribeAsync(observableEvent, QualityOfServiceLevelType.AtLeastOnce, ObserveEvent).ContinueWith(SendMessages); } catch (Exception ex) { PrintMessage("Error", ConsoleColor.Red, true); PrintMessage(ex.Message, ConsoleColor.Red); Console.ReadKey(); } }
static async Task StartMqttClientAsync(string token) { ConnectAckCode code = await MqttConnectAsync(token); if (code != ConnectAckCode.ConnectionAccepted) { return; } string observableEvent = !string.IsNullOrEmpty(pubResource) ? subResource : role == "A" ? resourceB : resourceA; //string observableEvent = role == "A" ? resourceB : resourceA; try { await mqttClient.SubscribeAsync(observableEvent, QualityOfServiceLevelType.AtLeastOnce, ObserveEvent).ContinueWith(SendMessages); } catch (Exception ex) { PrintMessage("Error", ConsoleColor.Red, true); PrintMessage(ex.Message, ConsoleColor.Red); Console.ReadKey(); } }
public async Task SubscribeAsync() { await mqttClient.SubscribeAsync(inputPiSystem, SkunkLab.Protocols.Mqtt.QualityOfServiceLevelType.AtMostOnce, DiagnosticsAction); }
public async Task OpenAsync() { await ExecuteRetryPolicy(); subscriptions.Clear(); if (channel != null) { try { channel.Dispose(); channel = null; client = null; logger?.LogDebug("Disposed internal channel."); } catch (Exception ex) { logger?.LogError(ex, "Fault disposing internal channel."); } } try { channel = new WebSocketClientChannel(endpointUrl, securityToken, "mqtt", new WebSocketConfig(), CancellationToken.None); client = new PiraeusMqttClient(new MqttConfig(180), channel); client.OnChannelError += Client_OnChannelError; client.OnChannelStateChange += Client_OnChannelStateChange; string sessionId = Guid.NewGuid().ToString(); ConnectAckCode code = await client.ConnectAsync(sessionId, "JWT", securityToken, 180); if (code != ConnectAckCode.ConnectionAccepted) { logger?.LogWarning($"Module client connect return code = '{code}'."); OnError?.Invoke(this, new ChannelErrorEventArgs(channel.Id, new Exception($"Module channel failed to open with code = {code}"))); } else { logger?.LogInformation("Module client connected."); foreach (var slave in config.Slaves) { string inputPiSystem = UriGenerator.GetRtuPiSystem(config.Hostname, config.VirtualRtuId, config.DeviceId, slave.UnitId, true); await client.SubscribeAsync(inputPiSystem, QualityOfServiceLevelType.AtMostOnce, ModuleReceived); logger?.LogDebug($"Module client subscribed to '{inputPiSystem}'"); } try { diag = new DiagnosticsChannel(config, client, logger); diag.StartAsync().GetAwaiter(); } catch (Exception ex) { diag = null; logger?.LogError(ex, "Diagnostics channel faulted."); } } } catch (Exception ex) { logger?.LogError(ex, "Fault opening module channel."); } }