At the moment Im simulating device where every 30 seconds I send telemetry data to IoT hub.
Here is simple code:
s_deviceClient = DeviceClient.Create(s_iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(s_myDeviceId, s_deviceKey), TransportType.Mqtt);
using var cts = new CancellationTokenSource();
var messages = SendDeviceToCloudMessagesAsync(cts.Token);
await s_deviceClient.CloseAsync(cts.Token);
await messages;
cts.Cancel();
And function to send message:
string combinedString = fileStrings[0] + fileStrings[1];
var telemetryDataString = converter.SerializeObject(combinedString);
using var message = new Message(Encoding.UTF8.GetBytes(telemetryDataString))
{
ContentEncoding = "utf-8",
ContentType = "application/json",
};
await s_deviceClient.SendEventAsync(message);
await Task.Delay(interval);
Everything works fine and I created .exe file that was running without problems. But computer where code is running tends to shut-off from time to time which is problematic. So I tried to move this to Azure Time Trigger Function. While in logs everything looks ok, messages aren't actually posted to IoT hub.
I tried to find solution but have not been able to find anything. Is it possible to send messages as device with azure function?
You seem to be closing your DeviceClient before you start using it to send messages. Try the following:
public async Task Do()
{
// Using statement will dispose your client after you're done with it.
// No need to close it manually.
using(var client = DeviceClient.Create(s_iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(s_myDeviceId, s_deviceKey), TransportType.Mqtt))
{
// Send messages, await for completion.
await SendDeviceToCloudMessagesAsync(client);
}
}
private async Task SendDeviceToCloudMessagesAsync(DeviceClient client)
{
string combinedString = fileStrings[0] + fileStrings[1];
var telemetryDataString = converter.SerializeObject(combinedString);
using var message = new Message(Encoding.UTF8.GetBytes(telemetryDataString))
{
ContentEncoding = "utf-8",
ContentType = "application/json",
};
await client.SendEventAsync(message);
await Task.Delay(interval);
}
Related
We are needing to write some software, that receives events one at a time, and we need to ingress them into ADX. We are struggling to understand how the Kusto Client is meant to be utilized.
public void SaveEvent(Object event)
{
var _kcsb = new KustoConnectionStringBuilder(Uri).WithAadApplicationKeyAuthentication(
applicationClientId: "{}",
applicationKey: "{}",
authority: TenantId);
using var ingestClient = KustoIngestFactory.CreateQueuedIngestClient(_kcsb);
//// Create your custom implementation of IRetryPolicy, which will affect how the ingest client handles retrying on transient failures
IRetryPolicy retryPolicy = new NoRetry();
//// This line sets the retry policy on the ingest client that will be enforced on every ingest call from here on
((IKustoQueuedIngestClient)ingestClient).QueueOptions.QueueRequestOptions.RetryPolicy = retryPolicy;
var ingestProperties = new KustoIngestionProperties(DatabaseName, TableName)
{
Format = DataSourceFormat.json,
IngestionMapping = new IngestionMapping { IngestionMappingKind = Kusto.Data.Ingestion.IngestionMappingKind.Json, IngestionMappingReference = MappingName }
};
// Build the stream
var stream = new MemoryStream();
using var streamWriter = new StreamWriter(stream: stream, encoding: Encoding.UTF8, bufferSize: 4096, leaveOpen: true);
using var jsonWriter = new JsonTextWriter(streamWriter);
packet.Id = DateTime.UtcNow.Ticks;
var serializer = new JsonSerializer();
serializer.Serialize(jsonWriter, event);
streamWriter.Flush();
stream.Seek(0, SeekOrigin.Begin);
// Tell the client to ingest this
await ingestClient.IngestFromStreamAsync(data, ingestProperties);
}
Now I have several concerns with this. We are calling this function 300 to 500 times a second. I believe the custom client has built in batching, but do we not then need to use a singleton instance of the custom client?
Next thing is that I am creating a steam per event and then calling ingerss. This feels wrong? is there no way I can setup the custom client etc, and then just enqueue each event into the custom client as we receiver them?
I have configured function apps in Azure to persist log entries from the function app insights logs to an event hub which then also persists these log entries to ELK. I recently noticed that some log entries were missing and I followed this example to create a console app that would replay the log events. The console app I created based on the examples works and no exceptions are thrown, however I never find the log entries when querying ELK, they don't appear to be persisted there the way I would expect. Below is some example code of what my console app is doing.
private const string connectionString = "CONNECTION_STRING";
private const string eventHubName = "EVENT_HUB_NAME";
static EventHubBufferedProducerClient producerClient;
static async Task Main()
{
string eventDataString = "{"message": "Here's a log entry"}";*/
var eventData = JsonConvert.DeserializeObject<EventData>(eventDataString);
eventData.MessageId = "MessageIDLog1";
eventData.ContentType = "application/json";
eventData.EventBody = new BinaryData(Encoding.UTF8.GetBytes("{message": "Here's a log entry}"));
producerClient = new EventHubBufferedProducerClient(connectionString, eventHubName);
producerClient.SendEventBatchFailedAsync += args =>
{
Console.WriteLine($"Publishing failed for { args.EventBatch.Count } events. Error: { args.Exception.Message }");
return Task.CompletedTask;
};
producerClient.SendEventBatchSucceededAsync += args =>
{
Console.WriteLine($"{ args.EventBatch.Count } events were published to partition: { args.PartitionId }.");
return Task.CompletedTask;
};
try
{
await producerClient.EnqueueEventAsync(eventData);
}
finally
{
await producerClient.DisposeAsync();
}
}
I'm hoping someone out there has some experience with this and could point me in the right direction as I've been on this for a while and I'm not sure what I'm doing incorrectly.
I have an azure function which makes a promise based http post request and gets a response; now I want to send this response to a service bus and to a different event hub (the azure function is being triggered by a different event hub).
function says it has been executed successfully in the case of event hub, but no events are being sent.
In the case of service bus I am getting this error NamespaceConnectionString should not contain EntityPath.
module.exports = async function (context, eventHubMessages) {
context.log(`JavaScript eventhub trigger function called for message array ${eventHubMessages}`);
var completeData = '';
eventHubMessages.forEach((message, index) => {
context.log(`Processed message ${message}`);
completeData = message;
});
var output = '';
const axios = require('axios');
try {
const response = await axios.post('http://fake-endpoint',
{ data-json : completeData
})
context.log(`statusCode: ${response.statusCode}`);
context.log(response.data);
output += response.data;
var time = new Date().toString();
context.log('Event Hub message created at: ', time);
context.bindings.outputEventHubMessage = out;
context.bindings.outputSbMsg = out;
context.done()
return response.data; // or return a custom object using properties from response
} catch (error) {
// If the promise rejects, an error will be thrown and caught here
context.done(error);
}
};
Expected output: successful execution; data available on service bus and event hub to receive.
Actual output: Error: NamespaceConnectionString should not contain EntityPath.
As the error message says, you need to look at your connection string and remove the EntityPath variable. This is included if you copy the connection string when viewing a specific topic or queue as opposed to copying it from the main Service Bus blade.
Endpoint=sb://{servicebus-name}.servicebus.windows.net/;SharedAccessKeyName=test-queue-sender;SharedAccessKey={SharedAccessKey}=;EntityPath=test-queue;
vs
Endpoint=sb://{servicebus-name}.servicebus.windows.net/;SharedAccessKeyName=test-queue-sender;SharedAccessKey={SharedAccessKey};
if I send a message (Cloud 2 Device) via the IoT-Hub:
var serviceMessage= new Message(Encoding.ASCII.GetBytes("Hello Device"));
serviceMessage.Ack = DeliveryAcknowledgement.Full;
commandMessage.MessageId = Guid.NewGuid().ToString();
await serviceClient.SendAsync("myDeviceID", serviceMessage); //Send message here
And try to receive the acknoledgement from the client:
bool feedbackReceived = false;
while(!feedbackReceived){
FeedbackReceiver<FeedbackBatch> feedbackReceiver = serviceClient.GetFeedbackReceiver();
var feedbackBatch = await feedbackReceiver.ReceiveAsync(TimeSpan.FromSeconds(1));
if(feedbackBatch != null)
{
feedbackReceived = feedbackBatch.Records.Any(fm => fm.OriginalMessageId == serviceMessage.MessageId);
if (feedbackReceived)
{
await feedbackReceiver.CompleteAsync(feedbackBatch);
feedbackReceiver = null;
}
}
}
My client gets the message immediatelly and sends an feedback:
DeviceClient deviceClient = DeviceClient.Create(iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(bridgeID, deviceKey), TransportType.Amqp);
Message receivedMessage = await deviceClient.ReceiveAsync();
await deviceClient.CompleteAsync(receivedMessage);
It take up to 15 seconds until my Cloud gets the feedback.
If I send messages in a loop, then the first message needs something between 1 and 15 sconds and every following response needs exactly 15 seconds.
Why does that need so long? Can I change it?
The receive-method in my cloud gets an answer immediatelly:
var incommingMessage = eventHubReceiver.ReceiveAsync();
incommingMessage.Wait();
If the client sends a message:
var message = new Message(Encoding.ASCII.GetBytes("My Message"));
await deviceClient.SendEventAsync(message);
A whole project with the problem is on gitHub:
https://github.com/Ben4485/Azure_IotHub_Get_Response
Of course 15 seconds are a lot. However, the feedback isn't a single message but always a batch (a JSON document with an array of feedback) that contains more feedbacks from more devices. It's possible that the system tries to acquire more feedback as possible before sending them to the system.
Paolo.
The web socket is written in javascript by my colleague. I managed to connect. First of all I have to log in on the application using a test account. I have to send the email and password through a json. I have installed the Json.Net packet using NuGet.
Some code that I found on my reaserch is this, but I do not understand how to send my data using that segment.
var buffer = new byte[1024];
var segment = new ArraySegment<byte>(buffer);
webSocket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
Of course, I can use an object
User user=new User();
user.Email="bla#bla.com";
user.Password="pass";
string json = JsonConvert.SerializeObject(user);
But it will not be of any use because the method SendAsync accepts only byte type on segment.
All I want is to send that data, and if log in succeeds, I should receive other data (in Json format) about the user.
As a side note, I am quite new to web sockets, I used http protocols from ASP.NET WEB API 2.
I have no idea about Windows Phone 8, but by the code you pasted it seems similar to the regular .NET ClientWebSocket, so here you have some examples:
public static Task SendString(ClientWebSocket ws, String data, CancellationToken cancellation)
{
var encoded = Encoding.UTF8.GetBytes(data);
var buffer = new ArraySegment<Byte>(encoded, 0, encoded.Length);
return ws.SendAsync(buffer, WebSocketMessageType.Text, true, cancellation);
}
public static async Task<String> ReadString(ClientWebSocket ws)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await ws.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms, Encoding.UTF8))
return reader.ReadToEnd();
}
}
If something does not compile or exists in WP8, just find an equivalent.
#vtortola is a working example in case your data comes in multiple segmented messages, but if all data comes in a single message you don't need all those streams to read the message, you just need to do this:
public static async Task<String> ReadString(ClientWebSocket socket)
{
var reciveBuffer = new byte[32000];
var result = await socket.ReceiveAsync(new ArraySegment<byte>(reciveBuffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
return Encoding.ASCII.GetString(reciveBuffer , 0, result.Count);
}
If your message is splited in multiple segments or you don't know how your message is comming then you have to do like #vtortola
Also if you want to keep receiving messages you can do a while and call ReadString inside, like this:
while (socket.State == WebSocketState.Open)
{
var msg = ReadString(socket)
//do something with your message...
}