I am new at Microsoft Azure IoT Hub. I want to get a list of devices in my IoT Hub and check if there are any devices in the list.
Its works fine if I use a console application.
static async void QueryDevices()
{
registryManager = RegistryManager.CreateFromConnectionString(DeviceConnectionString);
var devices = await registryManager.GetDevicesAsync(100); // Time 1 sek
foreach (var item in devices)
{
Console.WriteLine("Divice id: " + item.Id + ", Connection state: " + item.ConnectionState);
}
Console.WriteLine("\nNumber of devices: " + devices.Count());
}
But if I use the "same" code in a WebAPI the GetDevicesAsync() keeps running and running without any result.
public bool CheckIoTHubConnection(string iotHubConnectionString)
{
registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
return CreateConnection().Result;
}
private async Task<bool> CreateConnection()
{
bool connectionOk = false;
try
{
// Gets all devices from IoT Hub
var result = await registryManager.GetDevicesAsync(10); // This never gets further
if (result.Any())
connectionOk = true;
}
catch (Exception ex)
{
connectionOk = false;
throw ex;
}
return connectionOk;
}
What am I doing wrong?
You can try with this code format:
...
System.Threading.ThreadPool.QueueUserWorkItem(a => CheckIoTHubConnection(iotHubConnStr));
...
It works for me.
For more information you can reference the initial post "Send to IoT hub from MVC Web API?".
And for the reason of this issue, #Jason Malinowski's answer may explains at a certain extent.
Related
I'm trying to write a small streamdeck plugin to connect my paired headphones after they have been paired to another device and haven't connected to my PC automatically. I basically want to kick off the same process as clicking Connect in the Windows 11 device list.
I'm able to enumerate my devices, find the correct device based on the device ID, and identify if it is already connected, but I'm not sure how to enable the music and chat connections if it's disconnected.
Here's basically what I have
string[] requestedProperties = {
"System.Devices.Aep.IsConnected",
};
var devices = await DeviceInformation.FindAllAsync(BluetoothDevice.GetDeviceSelector(), requestedProperties);
foreach (DeviceInformation di in devices) {
if (!di.Properties.ContainsKey("System.Devices.Aep.IsConnected")) {
continue;
}
if (di.Properties[ConnectedKey] is true) {
Debug.WriteLine($"Connected Device Name {di.Name}");
Debug.WriteLine($"Connected Device Id {di.Id}");
continue;
}
if ("<myHeadphonesBluetoothId>" == di.Id) {
// Not sure where to go at this point to initiate those connections
}
}
Been googling for hours without any success, and given some attempts at the AudioPlaybackConnection, BluetoothDevice, and RfcommDeviceService classes without success.
My big issue was a misunderstanding in the architecture involved in the way that devices, services, etc work.
I was able to get a small sample app working targeting net6.0-windows10.0.22000.0
const string targetDeviceId = "Bluetooth#Bluetooth00:00:00:00:00:00-00:00:00:0:0:00";
const int serialPortShortId = 0x1101;
using var streamSocket = new StreamSocket();
await EstablishConnection();
async ValueTask EstablishConnection() {
RfcommServiceId targetServiceId = RfcommServiceId.FromShortId(serialPortShortId);
BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync();
if (adapter is not null)
{
Radio btRadio = await adapter.GetRadioAsync();
if (btRadio.State == RadioState.Off)
{
await btRadio.SetStateAsync(RadioState.On);
Console.WriteLine("Bluetooth adapter was off. Turned it on.");
}
}
using BluetoothDevice btDevice = await BluetoothDevice.FromIdAsync(targetDeviceId);
btDevice.ConnectionStatusChanged += (sender, args) => Console.WriteLine("Bluetooth device connected");
RfcommDeviceServicesResult services = await btDevice.GetRfcommServicesForIdAsync(targetServiceId);
RfcommDeviceService service = services.Services.Single();
if (btDevice.ConnectionStatus != BluetoothConnectionStatus.Connected && service.DeviceAccessInformation.CurrentStatus == DeviceAccessStatus.Allowed) {
try {
await streamSocket.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName,
SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
}
catch (COMException e) when ((uint)e.HResult == 0x8007277C) {
Console.WriteLine("Bluetooth device is not on or in range.");
}
}
}
After running this the device would connect and windows would initialize the mic and speaker devices attached to it.
I have the code in .NET CORE deployed on windows works fine when c# mongo db client access the document. However when the same code is deployed on linux machine takes 15 minutes to fetch the document and it happens intermittently. I also updated the MongoDb driver to 2.10.4 but it didn't work for me.
// Code trying to fetch Document from web api , calling library method to fetch document
MongoDbService _mongoDbClient = new MongoDbService(_configuration["MongoDBConnection"]);
Conversation storedmodel = new Conversation ();
for (int i = 0; i < 10; i++)
{
try
{
storedmodel = _mongoDbClient.GetDocumentFromConversationId(ConversationId);
break;
}
catch (Exception ex)
{
if (i == 9)
{
//Logging exception
LumenTelemetry.TrackEvent(conversationID, " Error - " + ex.Message + " " + ex.InnerException + " " + ex.StackTrace);
}
}
}
//////////////////////// Code in Library Project
public interface IMongoService
{
IMongoDatabase GetDatabase(string dbName);
Conversation GetDocumentFromConversationId(string conversationId);
}
public class MongoDbService : IMongoService
{
private readonly MongoClient _mongoClient;
public MongoDbService(string conStr)
{
var connection = new MongoDbConnection(conStr);
_mongoClient = connection.MongoConnection;
}
public Conversation GetDocumentFromConversationId(string conversationId)
{
IMongoDatabase db = _mongoClient.GetDatabase("ConversationDb");
var collection = db.GetCollection<Conversation>("ConversationCollection/documents");
var document = collection.Find(doc => doc.ConversationId == conversationId).FirstOrDefault();
return document;
}
}
Enable logging to troubleshoot:
command monitoring in the driver
look at server logs
Identify where the time is spent:
prior to anything mongodb-related happening? (problem in your application unrelated to mongodb)
server selection
query write/request
query processing on server
Play with server selection timeout, connect timeout, socket timeout & maxTimeMS to identify the cause.
So... I'm working with a third-party library (zkemkeeper.dll) to make a winform applicaction to manage attendance devices. I'm trying to get several devices connected and attach some events to listen for some actions they will fire. Everithing it's fine running all sync. I run some methods and for each device I try to connect like this:
public bool connect(Device myDevice)
{
bool result=false;
if (!myDevice.isConn)
{
myDevice.zkDevice = null;
myDevice.zkDevice = new CZKEMClass();
myDevice.zkDevice.MachineNumber = myDevice.id;
if (myDevice.password.HasValue)
{
myDevice.zkDevice.SetCommPassword(myDevice.password.Value);
}
try
{
result = myDevice.zkDevice.Connect_Net(myDevice.ip, myDevice.port);
myDevice.error = result ? "" : "Could not connect to device";
}
catch (Exception ex)
{
myDevice.error = ex.Message;
result = false;
}
if(result)
{
//Bind events
if (myDevice.zkDevice.RegEvent(myDevice.id, 1))
{
myDevice.zkDevice.OnAttTransactionEx += new _IZKEMEvents_OnAttTransactionExEventHandler(device_OnTransactionEx);
}
}
myDevice.zkDevice.EnableDevice(myDevice.id, true);
myDevice.zkDevice.EnableClock(1);
}
return result;
}
My main problem is that this take a couple of seconds to connect to each device depending on the state of the network, so if I have 50 or 100 device the interface will freeze every time a device is connected or reconnected and this will make a huge delay.(besides that the application must always be functional)
Ok to solve that I use this:
private async Task connectAllAsync()
{
List<Task<bool>> lstTasks = new List<Task<bool>>();
foreach (var device in lstDevices)
{
lstTasks.Add(Task.Run(() => connect(device)));
}
var arrayComplete =await Task.WhenAll(lstTasks);
int countErr=arrayComplete.ToList().Where(n => n == false).Count();
if(countErr>0)
{
timerReconnect.Enabled = true;
}
}
After this the interface doesn't freeze,my connection to all devices is faster,even if I try to interrogate any device for information the device respond BUT when I try to trigger any event these doesnt fire, I dont know where is my mistake I think it could be related to atach the event on another thread or something like that... Help me give me some way to go, thanks in advance.
Edit: Im also tried making the "connect" function async an make it await for the Connect_Net response (which is part of the third party code)
You have an uncaptured closure. Try this:
foreach (var device in lstDevices)
{
var captured = device;
lstTasks.Add(Task.Run(() => connect(captured)));
}
Or just use LINQ to do it all:
lstTasks = lstDevices.Select
(
device => Task.Run
(
() => connect(device)
)
);
A totally different approach would get rid of Task.Run() and use Parallel.ForEach instead. If you use this approach, you'd have to store the results in a thread-safe container like ConcurrentBag<>.
var results = new ConcurrentBag<bool>();
Parallel.ForEach
(
lstDevices,
device =>
{
results.Add(connect(device));
}
);
int countErr = results.Count( x => x == false );
Or you could just use a counter:
volatile int countErr = 0;
Parallel.ForEach
(
lstDevices,
device =>
{
var ok = results.Add(connect(device));
if (!ok) Interlocked.Increment(ref countErr);
}
);
I'm using a DeviceWatcher to get the DeviceInformation for a paired Bluetooth device in a UWP app. I set the DeviceWatcher up like this
var requestedProperties = new string[] { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
var deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\")", requestedProperties, DeviceInformationKind.AssociationEndpoint); // ClassGuid = {e0cbf06c-cd8b-4647-bb8a-263b43f0f974} includes all Bluetooth devices
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Start();
When the DeviceWatcher_Added event handler is called I check to see if the device is the one I am interested in by checking its name and that it offers the RfcommServiceId.SerialPort.Uuid service.
Once I have the DeviceInformation for the bluetooth device I am interested in how do I get the COM port for it? I can see it in the Device Manager, where it is listed as "Standard Serial over Bluetooth link (COM8)", but I cannot see how to get that "COM8" in UWP programmatically.
I've tried making the DeviceInformation into a SerialDevice, whereby I could then get SerialDevice.PortName (c.f. this answer) but my call to SerialDevice.FromIdAsync(deviceInfo.Id) fails with a System.Exception: The data is invalid.
(N.B. Some tantalizing answers, like this and this, use the Windows Management Intrumentation WMI functions but these are not available in UWP.)
On another question Rita suggested looking at the Serial UART sample which helped me see a way to do this. I won't mark this as the answer for a while as it seems too indirect to be the canonical way.
Although I have the the DeviceInformation for the paired Bluetooth device in my UWP app I also need the list of SerialDevices so that I can match them up. Here's the resulting code.
public async Task<string> ComPort(DeviceInformation deviceInfo)
{
var serialDevices = new Dictionary<string, SerialDevice>();
var serialSelector = SerialDevice.GetDeviceSelector();
var serialDeviceInformations = (await DeviceInformation.FindAllAsync(serialSelector)).ToList();
var hostNames = NetworkInformation.GetHostNames().Select(hostName => hostName.DisplayName.ToUpper()).ToList(); // So we can ignore inbuilt ports
foreach (var serialDeviceInformation in serialDeviceInformations)
{
if (hostNames.FirstOrDefault(hostName => hostName.StartsWith(serialDeviceInformation.Name.ToUpper())) == null)
{
try
{
var serialDevice = await SerialDevice.FromIdAsync(serialDeviceInformation.Id);
if (serialDevice != null)
{
serialDevices.Add(deviceInfo.Id, serialDevice);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
}
// Example Bluetooth DeviceInfo.Id: "Bluetooth#Bluetooth9c:b6:d0:d6:d7:56-00:07:80:cb:56:6d"
// from device with Association Endpoint Address: "00:07:80:cb:56:6d"
var lengthOfTrailingAssociationEndpointAddresss = (2 * 6) + 5;
var bluetoothDeviceAddress = deviceInfo.Id.Substring(deviceInfo.Id.Length - lengthOfTrailingAssociationEndpointAddresss, lengthOfTrailingAssociationEndpointAddresss).Replace(":", "").ToUpper();
var matchingKey = serialDevices.Keys.FirstOrDefault(id => id.Contains(bluetoothDeviceAddress));
if (matchingKey != null)
{
return serialDevices[matchingKey].PortName;
}
return "";
}
I'm new to the Azure Service Bus and am working on a proof of concept using Service Bus Queues, WebJobs, v2.5 of the Azure SDK and Visual Studio 2013
Enqueuing and de-queuing messages from the bus is pretty straightforward, but in order to implement a request-response pattern it looks like I need to use sessions, and that's where the wheels have come off.
Here's the proof-of-concept code from the WebJobs project. It requires that you create two service bus queues: test-request and test-response. The response queue must have Enable Sessions = true
class Program
{
private static string _azureServiceBusConnection;
static void Main()
{
_azureServiceBusConnection = ConfigurationManager.ConnectionStrings["AzureWebJobsServiceBus"].ConnectionString;
var host = new JobHost();
Task.Factory.StartNew(() => Run());
try
{
host.RunAndBlock();
}
catch (Exception ex)
{
Console.WriteLine("RunAndBlock() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
}
private static async Task Run()
{
await Task.Delay(1000);
var request = QueueClient.CreateFromConnectionString(_azureServiceBusConnection, "test-request");
var response = QueueClient.CreateFromConnectionString(_azureServiceBusConnection, "test-response");
var sessionid = Guid.NewGuid().ToString();
MessageSession receiver;
try
{
receiver = response.AcceptMessageSession(sessionid);
}
catch (Exception ex )
{
Console.WriteLine("AcceptMessageSession() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
var payload = new RequestModel {ID = Guid.NewGuid(), Delay = 1};
var message = new BrokeredMessage(payload) {ReplyToSessionId = sessionid};
try
{
request.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Send() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
var receivedMessage = receiver.Receive(TimeSpan.FromSeconds(5));
if (receivedMessage != null)
{
// Request processed within the timeout period
var responseBody = receivedMessage.GetBody<RequestModel>();
Console.WriteLine("Inline response to {0}", responseBody.ID );
receivedMessage.Complete();
}
else
{
// Request processing timed out - should be handled by LocalResponseQueue WebJob (see below)
Console.WriteLine("ERROR: Response timed out.");
}
}
}
public class RequestModel
{
public Guid ID { get; set; }
public int Delay { get; set; }
}
public class RemoteSystemRequestQueue
{
// Simulates the processing of the request on a remote system
public static void ProcessQueueMessage([ServiceBusTrigger("test-request")] BrokeredMessage request, [ServiceBus("test-response")] out BrokeredMessage response)
{
// Wait for the prescribed delay, then bounce the request payload back via the response queue
var requestBody = request.GetBody<RequestModel>();
Console.WriteLine("Recieved Request {0}, delay={1}", requestBody.ID, requestBody.Delay);
Task.Delay(requestBody.Delay * 1000).Wait();
response = new BrokeredMessage(requestBody) {SessionId = request.ReplyToSessionId};
request.Complete();
Console.WriteLine("Completed Request {0}, delay={1}", requestBody.ID, requestBody.Delay);
}
}
public class LocalResponseQueue
{
// Should be called ONLY when the processing took longer than the timeout
public static void ProcessQueueMessage([ServiceBusTrigger("test-response")] BrokeredMessage message, TextWriter logger)
{
var msgBody = message.GetBody<RequestModel>();
Console.WriteLine("ResponseFactory Recieved Reply {0}", msgBody.ID);
}
}
When Enable Sessions = true on the test-response queue, the call to host.RunAndBlock() throws a System.InvalidOperationException with the message
It is not possible for an entity that requires sessions to create a non-sessionful message receiver
The output looks like this:
Found the following functions:
ServiceBusPoc.RemoteSystemRequestQueue.ProcessQueueMessage
ServiceBusPoc.LocalResponseQueue.ProcessQueueMessage
Executing: 'RemoteSystemRequestQueue.ProcessQueueMessage' because New service bus message detected on 'test-request'.
Recieved Request 4f000f8f-dd69-4909-9ec4-020fec12366c, delay=1
RunAndBlock() Unexpected System.InvalidOperationException: It is not possible for an entity that requires sessions to create a non-sessionful message receiver.
TrackingId:7836ac90-6920-4e6c-b7f1-cf648e2a17e5_G38_B10,TimeStamp:10/6/2015 12:37:05 PM
Note that the exception was thrown BEFORE the RemoteSystemRequestQueue object could complete processing the queued request
I presume from this that this means that WebJobs can't handle sessions (at least in the manner in which I'm using them)
Can anyone shed any light on this, or am I going to have to give up on WebJobs?
What version of the WebJobs SDK are you using? In our current v1.1.0 release (still prerelease) we've started opening up more options for ServiceBus configuration. See:
ServiceBusConfiguration
Custom MessagingProvider
You can basically now control more of the messaging details that were previously buried in the SDK internals. However, regarding full Session support, we do have this open issue that might be closer to your scenario. If so, and if you can't get things to work with the above, please add your scenario details to that issue. Thanks.