private ReceivedUdpData GetMockByeByeNotification(SsdpDevice device) { var data = String.Format(@"NOTIFY * HTTP/1.1 HOST: 239.255.255.250:1900 DATE: {0} NT: {1} NTS: ssdp:byebye SERVER: TestOS/1.0 UPnP/1.0 RSSDP/1.0 USN: {2} ", DateTime.UtcNow.ToString("r"), device.Udn, String.Format("{0}::{1}", device.Udn, device.FullDeviceType) ); var retVal = new ReceivedUdpData() { Buffer = System.Text.UTF8Encoding.UTF8.GetBytes(data), ReceivedFrom = new UdpEndPoint() { IPAddress = SsdpConstants.MulticastLocalAdminAddress, Port = 1900 } }; retVal.ReceivedBytes = retVal.Buffer.Length; return(retVal); }
private void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, UdpEndPoint endPoint) { var rootDevice = device.ToRootDevice(); var additionalheaders = FormatCustomHeadersForResponse(device); string message; if (device.Weemo) { message = String.Format(WeemoSearchResponseMessageFormat, String.Format("CACHE-CONTROL: max-age={0}", rootDevice.CacheLifetime.TotalSeconds), DateTime.UtcNow.ToString("r"), rootDevice.Location, rootDevice.SerialNumber, searchTarget, uniqueServiceName); } else { message = String.Format(DeviceSearchResponseMessageFormat, CacheControlHeaderFromTimeSpan(rootDevice), searchTarget, uniqueServiceName, rootDevice.Location, _OSName, _OSVersion, ServerVersion, DateTime.UtcNow.ToString("r"), additionalheaders); } _CommsServer.SendMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message), endPoint); WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device); }
private ReceivedUdpData GetMockSearchResponseWithCustomCacheHeader(SsdpDevice device, string stHeader, string cacheHeader) { var responseText = String.Format(@"HTTP/1.1 200 OK EXT: DATE: {4}{0} ST:{1} SERVER: TestOS/1.0 UPnP/1.0 RSSDP/1.0 USN:{2} LOCATION:{3} ", //Blank line at end important, do not remove. String.IsNullOrEmpty(cacheHeader) ? String.Empty : Environment.NewLine + cacheHeader, stHeader, String.Format("{0}:{1}", device.Udn, device.FullDeviceType), device.ToRootDevice().Location, DateTime.UtcNow.ToString("r") ); var retVal = new ReceivedUdpData() { Buffer = System.Text.ASCIIEncoding.UTF8.GetBytes(responseText), ReceivedFrom = new UdpEndPoint() { IPAddress = SsdpConstants.MulticastLocalAdminAddress, Port = SsdpConstants.MulticastPort } }; retVal.ReceivedBytes = retVal.Buffer.Length; return(retVal); }
private void AddDevice(DiscoveredSsdpDevice device, SsdpDevice fullDevice) { var existingDevice = deviceList.FirstOrDefault(d => d.GetHost().Equals(device.DescriptionLocation.Host)); if (existingDevice == null) { if (!deviceList.Any(d => d.GetUsn().Equals(device.Usn))) { var newDevice = DependencyFactory.Container.Resolve <Device>(); newDevice.SetDiscoveredDevices(device, fullDevice); deviceList.Add(newDevice); onAddDeviceCallback?.Invoke(newDevice); if (AutoStart) { newDevice.OnClickDeviceButton(null, null); } } } else { existingDevice.SetDiscoveredDevices(device, fullDevice); existingDevice.GetDeviceControl()?.SetDeviceName(existingDevice.GetFriendlyName()); existingDevice.GetMenuItem().Text = existingDevice.GetFriendlyName(); } }
private void SendAliveNotifications(SsdpDevice device, bool isRoot) { if (isRoot) { SendAliveNotification(device, device.NotificationType ?? SsdpConstants.UpnpDeviceTypeRootDevice, device.Usn ?? GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice)); #pragma warning disable CS0618 // Type or member is obsolete if (this.SupportPnpRootDevice) #pragma warning restore CS0618 // Type or member is obsolete { SendAliveNotification(device, SsdpConstants.PnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice)); } } SendAliveNotification(device, device.Udn, device.Udn); SendAliveNotification(device, device.FullDeviceType, GetUsn(device.Udn, device.FullDeviceType)); foreach (var service in device.Services) { SendAliveNotification(device, service); } foreach (var childDevice in device.Devices) { SendAliveNotifications(childDevice, false); } }
private async void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress) { var rootDevice = device.ToRootDevice(); //var additionalheaders = FormatCustomHeadersForResponse(device); const string header = "HTTP/1.1 200 OK"; var values = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); values["EXT"] = ""; values["DATE"] = DateTime.UtcNow.ToString("r"); values["CACHE-CONTROL"] = "max-age = 600"; values["ST"] = searchTarget; values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); values["USN"] = uniqueServiceName; values["LOCATION"] = rootDevice.Location.ToString(); var message = SsdpHelper.BuildMessage(header, values); try { await _CommsServer.SendMessage(System.Text.Encoding.UTF8.GetBytes(message), endPoint, receivedOnlocalIpAddress).ConfigureAwait(false); } catch (Exception ex) { } //WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device); }
// Process each found device in the event handler private async void deviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs e) { if (DeviceFoundEvent == null) { return; } //Device data returned only contains basic device details and location of full device description. //Console.WriteLine("Found " + e.DiscoveredDevice.Usn + " at " + e.DiscoveredDevice.DescriptionLocation.ToString()); //Can retrieve the full device description easily though. try { SsdpDevice fullDevice = await e.DiscoveredDevice.GetDeviceInfo().ConfigureAwait(false); } catch (Exception ex) { // ToDo: Error Handling return; } DeviceFoundEventArgs eventArgs = new DeviceFoundEventArgs(); eventArgs.Usn = e.DiscoveredDevice.Usn; eventArgs.DescriptionLocation = e.DiscoveredDevice.DescriptionLocation.ToString(); //eventArgs.FriendlyName = fullDevice.FriendlyName; DeviceFoundEvent(this, eventArgs); }
private static void ValidateChildServices(SsdpDevice device, List <string> retVal) { foreach (var service in device.Services) { ValidateService(service, retVal); } }
private byte[] BuildAliveMessage(SsdpDevice device, string notificationType, string uniqueServiceName, string hostAddress) { var rootDevice = device.ToRootDevice(); var additionalheaders = FormatCustomHeadersForResponse(device); return(System.Text.UTF8Encoding.UTF8.GetBytes ( String.Format ( AliveNotificationMessageFormat, notificationType, uniqueServiceName, rootDevice.Location, CacheControlHeaderFromTimeSpan(rootDevice), _OSName, _OSVersion, ServerVersion, DateTime.UtcNow.ToString("r"), hostAddress, SsdpConstants.MulticastPort, additionalheaders ) )); }
/// <summary> /// Searches the specified IP Address. /// //string IP, string term) /// </summary> public async Task Search() { try { var foundDevices = await deviceLocator.SearchAsync().ConfigureAwait(false); foreach (DiscoveredSsdpDevice device in foundDevices.ToList()) { SsdpDevice info = await device.GetDeviceInfo().ConfigureAwait(false); var fd = new FoundDevice { IpAddress = device.DescriptionLocation.DnsSafeHost, DeviceName = info.FriendlyName, DeviceId = info.Uuid.Replace("-", ""), FoundUsing = "SSdp", FoundAt = device.AsAt.DateTime }; FoundDeviceCollection.Add(fd); } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"\t{ex.Message}"); Console.ResetColor(); } }
public async Task <List <DiscoveredSsdpDevice> > Search() { deviceLocator = new SsdpDeviceLocator(); try { var foundDevices = deviceLocator.SearchAsync().Result.ToList(); if (foundDevices.Count > 0) { foreach (var device in foundDevices) { SsdpDevice info = await device.GetDeviceInfo().ConfigureAwait(false); var objs = new List <object> { device, info }; var foundDevice = auow.BuildObject <FoundDevice, List <object> >(objs); auow.Commit(foundDevice); } } return(foundDevices.ToList()); } catch (SocketException ex) { Console.WriteLine(ex.Message); throw; } }
private void SendByeByeNotifications(SsdpDevice device, bool isRoot) { if (isRoot) { SendByeByeNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice)); #pragma warning disable CS0618 // Type or member is obsolete if (this.SupportPnpRootDevice) #pragma warning restore CS0618 // Type or member is obsolete { SendByeByeNotification(device, "pnp:rootdevice", GetUsn(device.Udn, "pnp:rootdevice")); } } SendByeByeNotification(device, device.Udn, device.Udn); SendByeByeNotification(device, String.Format("urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType)); foreach (var service in device.Services) { SendByeByeNotification(device, service); } foreach (var childDevice in device.Devices) { SendByeByeNotifications(childDevice, false); } }
public DeviceViewModel(DiscoveredSsdpDevice discoveredDevice, SsdpDevice device) { this.discoveredDevice = discoveredDevice ?? throw new ArgumentNullException(nameof(discoveredDevice)); this.device = device ?? throw new ArgumentNullException(nameof(device)); State = DeviceState.NotConnected; PlayCommand = new RelayCommand(PlayAsync, () => CanPlay); PauseCommand = new RelayCommand(PauseAsync, () => CanPause); StopCommand = new RelayCommand(StopAsync, () => CanStop); UpdateCommandStatus(); deviceConnection = new EndpointConnection(Host); deviceCommunication = new EndpointCommunication(deviceConnection); var syncContext = SynchronizationContext.Current; deviceCommunication.StateChanged += (EndpointCommunication com, DeviceState newState) => { syncContext.Post((_) => { State = newState; UpdateCommandStatus(); }, null); }; deviceCommunication.PlayingTimeChanged += delegate { syncContext.Post((_) => { AudioDelay = TimeSpan.FromSeconds(Math.Max(0, (playWatch.Elapsed - deviceCommunication.PlayingTime).TotalSeconds)); }, null); }; }
async private Task <ISensorItem> CreateVideoSensor( SsdpDevice fullDevice, string serialNumber, IDeviceItem videoCameraDeviceItem) { ISensorItem sensor = null; // We need to do this in the UI thread since it may cause some UI elements to be updated. await DispatcherHelper.UIDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() => { sensor = new SensorItem(videoCameraDeviceItem.DeviceId) { Description = (fullDevice.FriendlyName ?? string.Empty), IsEnabled = true, SensorType = SensorType.VideoCamera, SensorUsage = SensorUsage.Other, SerialNumber = serialNumber, }; sensor = await App.SensorCollection.BeginAdd(sensor); }); Debug.Assert(null != sensor); return(sensor); }
async private Task <IDeviceItem> CreateVideoDevice( SsdpDevice fullDevice, string serialNumber) { IDeviceItem device = null; // We need to do this in the UI thread since it may cause some UI elements to be updated. await DispatcherHelper.UIDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() => { device = new DeviceItem() { Description = (fullDevice.FriendlyName ?? string.Empty), DeviceType = DeviceType.IPCamera, FirmwareVersion = fullDevice.DeviceVersion.ToString(), IPAddress = (null != fullDevice.PresentationUrl ? fullDevice.PresentationUrl.ToString() : string.Empty), IsOnline = true, Location = "Video camera location", // BUGBUG - localize this. Manufacturer = fullDevice.Manufacturer, Model = (fullDevice.ModelNumber ?? string.Empty), Name = (fullDevice.ModelName ?? string.Empty), IsVirtual = false, SerialNumber = serialNumber, }; device = await App.DeviceCollection.BeginAdd(device); }); Debug.Assert(null != device); return(device); }
private static void WriteOutDevices(SsdpDevice device) { Console.WriteLine(device.Udn + " - " + device.FullDeviceType); foreach (var childDevice in device.Devices) { WriteOutDevices(device); } }
/// <summary> /// Validates the specified device and throws an <see cref="System.InvalidOperationException"/> if there are any validation errors. /// </summary> /// <param name="device">The <see cref="SsdpDevice"/> to validate.</param> /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception> /// <exception cref="System.InvalidOperationException">Thrown if the device object does not pass validation.</exception> public void ThrowIfDeviceInvalid(SsdpDevice device) { var errors = this.GetValidationErrors(device); if (errors != null && errors.Any()) { throw new InvalidOperationException("Invalid device settings : " + String.Join(Environment.NewLine, errors)); } }
private void NavigateCommandAction(SsdpDevice device) { if (device == null) { return; } _navigationService.NavigateTo(ViewModelLocator.NetworkSelectPageKey, device); }
private void ValidateChildDevices(SsdpDevice device, List <string> retVal) { foreach (var childDevice in device.Devices) { foreach (var validationError in this.GetValidationErrors(childDevice)) { retVal.Add("Embedded Device : " + childDevice.Uuid + ": " + validationError); } } }
private void DisconnectFromDeviceEvents(SsdpDevice device) { device.DeviceAdded -= device_DeviceAdded; device.DeviceRemoved -= device_DeviceRemoved; foreach (var childDevice in device.Devices) { DisconnectFromDeviceEvents(childDevice); } }
private void ConnectToDeviceEvents(SsdpDevice device) { device.DeviceAdded += device_DeviceAdded; device.DeviceRemoved += device_DeviceRemoved; foreach (var childDevice in device.Devices) { ConnectToDeviceEvents(childDevice); } }
private static void ValidateUdn(SsdpDevice device, List <string> retVal) { if (!device.Udn.StartsWith("uuid:", StringComparison.OrdinalIgnoreCase)) { retVal.Add("UDN must begin with uuid:. Correct format is uuid:<uuid>"); } else if (device.Udn.Substring(5).Trim() != device.Uuid) { retVal.Add("UDN incorrect. Correct format is uuid:<uuid>"); } }
private void SetProperies(SsdpDevice device, string fullDeviceType) { var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty); var serviceParts = service.Split(':'); var deviceTypeNamespace = serviceParts[0].Replace('.', '-'); device.DeviceTypeNamespace = deviceTypeNamespace; device.DeviceClass = serviceParts[1]; device.DeviceType = serviceParts[2]; }
private void SendDeviceSearchResponses(SsdpDevice device, string searchTarget, UdpEndPoint endPoint) { //http://www.upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0-20080424.pdf - page 21 //For ssdp:all - Respond 3+2d+k times for a root device with d embedded devices and s embedded services but only k distinct service types //Root devices - Respond once (special handling when in related/Win Explorer support mode) //Udn (uuid) - Response once //Device type - response once //Service type - respond once per service type bool isRootDevice = (device as SsdpRootDevice) != null; bool sendAll = searchTarget == SsdpConstants.SsdpDiscoverAllSTHeader; bool sendRootDevices = searchTarget == SsdpConstants.UpnpDeviceTypeRootDevice || searchTarget == SsdpConstants.PnpDeviceTypeRootDevice; if (isRootDevice && device.NotificationType == searchTarget) { SendSearchResponse(device.NotificationType, device, device.Usn ?? GetUsn(device.Udn, searchTarget), endPoint); } else if (isRootDevice && (sendAll || sendRootDevices)) { SendSearchResponse(device.NotificationType ?? SsdpConstants.UpnpDeviceTypeRootDevice, device, device.Usn ?? GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint); if (IsWindowsExplorerSupportEnabled) { SendSearchResponse(device.NotificationType ?? SsdpConstants.PnpDeviceTypeRootDevice, device, device.Usn ?? GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), endPoint); } } if (sendAll || searchTarget.StartsWith("uuid:", StringComparison.Ordinal)) { SendSearchResponse(device.Udn, device, device.Udn, endPoint); } if (sendAll || searchTarget.Contains(":device:")) { SendSearchResponse(device.FullDeviceType, device, GetUsn(device.Udn, device.FullDeviceType), endPoint); } if (searchTarget == SsdpConstants.SsdpDiscoverAllSTHeader) { //Send 1 search response for each unique service type for all devices found var serviceTypes = ( from s in device.Services select s.FullServiceType ).Distinct().ToArray(); foreach (var st in serviceTypes) { SendServiceSearchResponses(device, st, endPoint); } } }
private static string GetDeviceEventLogMessage(string text, SsdpDevice device) { var rootDevice = device as SsdpRootDevice; if (rootDevice != null) { return(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); } else { return(text + " " + device.DeviceType + " - " + device.Uuid); } }
private void SendDeviceSearchResponses(SsdpDevice device, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken) { bool isRootDevice = (device as SsdpRootDevice) != null; if (isRootDevice) { SendSearchResponse(SsdpConstants.UpnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint, receivedOnlocalIpAddress, cancellationToken); } SendSearchResponse(device.Udn, device, device.Udn, endPoint, receivedOnlocalIpAddress, cancellationToken); SendSearchResponse(device.FullDeviceType, device, GetUsn(device.Udn, device.FullDeviceType), endPoint, receivedOnlocalIpAddress, cancellationToken); }
private static void WriteTrace(string text, SsdpDevice device) { var rootDevice = device as SsdpRootDevice; if (rootDevice != null) { WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); } else { WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid); } }
private void SendByeByeNotification(SsdpDevice device, string notificationType, string uniqueServiceName) { string multicastIpAddress = _CommsServer.DeviceNetworkType.GetMulticastIPAddress(); var multicastMessage = BuildByeByeMessage(notificationType, uniqueServiceName, multicastIpAddress); _CommsServer.SendMessage(multicastMessage, new UdpEndPoint { IPAddress = multicastIpAddress, Port = SsdpConstants.MulticastPort }); LogDeviceEvent(String.Format("Sent byebye notification, NT={0}, USN={1}", notificationType, uniqueServiceName), device); }
private void SendAliveNotifications(SsdpDevice device, bool isRoot, CancellationToken cancellationToken) { if (isRoot) { SendAliveNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), cancellationToken); } SendAliveNotification(device, device.Udn, device.Udn, cancellationToken); SendAliveNotification(device, device.FullDeviceType, GetUsn(device.Udn, device.FullDeviceType), cancellationToken); foreach (var childDevice in device.Devices) { SendAliveNotifications(childDevice, false, cancellationToken); } }
private void SendByeByeNotification(SsdpDevice device, string notificationType, string uniqueServiceName) { var message = String.Format(ByeByeNotificationMessageFormat, notificationType, uniqueServiceName, _OSName, _OSVersion, ServerVersion, DateTime.UtcNow.ToString("r") ); _CommsServer.SendMulticastMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message)); WriteTrace(String.Format("Sent byebye notification"), device); }
private static void WriteTrace(string text, SsdpDevice device) { var rootDevice = device as SsdpRootDevice; if (rootDevice != null) WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); else WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid); }
private void SendByeByeNotifications(SsdpDevice device, bool isRoot) { if (isRoot) { SendByeByeNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice)); if (this.SupportPnpRootDevice) SendByeByeNotification(device, "pnp:rootdevice", GetUsn(device.Udn, "pnp:rootdevice")); } SendByeByeNotification(device, device.Udn, device.Udn); SendByeByeNotification(device, String.Format("urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType)); foreach (var childDevice in device.Devices) { SendByeByeNotifications(childDevice, false); } }
private void SendDeviceSearchResponses(SsdpDevice device, UdpEndPoint endPoint) { bool isRootDevice = (device as SsdpRootDevice) != null; if (isRootDevice) { SendSearchResponse(SsdpConstants.UpnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint); if (this.SupportPnpRootDevice) SendSearchResponse(SsdpConstants.PnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), endPoint); } SendSearchResponse(device.Udn, device, device.Udn, endPoint); SendSearchResponse(device.FullDeviceType, device, GetUsn(device.Udn, device.FullDeviceType), endPoint); }
private static string FormatCustomHeadersForResponse(SsdpDevice device) { if (device.CustomResponseHeaders.Count == 0) return String.Empty; StringBuilder returnValue = new StringBuilder(); foreach (var header in device.CustomResponseHeaders) { returnValue.Append("\r\n"); returnValue.Append(header.ToString()); } return returnValue.ToString(); }
private void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, UdpEndPoint endPoint) { var rootDevice = device.ToRootDevice(); var message = String.Format(DeviceSearchResponseMessageFormat, CacheControlHeaderFromTimeSpan(rootDevice), searchTarget, uniqueServiceName, rootDevice.Location, _OSName, _OSVersion, ServerVersion, DateTime.UtcNow.ToString("r") ); _CommsServer.SendMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message), endPoint); WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device); }
private void SendAliveNotifications(SsdpDevice device, bool isRoot) { if (isRoot) { SendAliveNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice)); if (this.SupportPnpRootDevice) SendAliveNotification(device, SsdpConstants.PnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice)); } SendAliveNotification(device, device.Udn, device.Udn); SendAliveNotification(device, device.FullDeviceType, GetUsn(device.Udn, device.FullDeviceType)); foreach (var childDevice in device.Devices) { SendAliveNotifications(childDevice, false); } }
private void SendAliveNotification(SsdpDevice device, string notificationType, string uniqueServiceName) { var rootDevice = device.ToRootDevice(); var message = String.Format(AliveNotificationMessageFormat, notificationType, uniqueServiceName, rootDevice.Location, CacheControlHeaderFromTimeSpan(rootDevice), _OSName, _OSVersion, ServerVersion, DateTime.UtcNow.ToString("r") ); _CommsServer.SendMulticastMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message)); WriteTrace(String.Format("Sent alive notification"), device); }