IoT Hub route query does not match on message body - azure-iot-hub

I'm facing some issues with filtering on message body in the Azure IoT Hub. Is this still not supported? The tests go through, but when I try real messages from the device everything is hitting the fallback and not the intended route.¨
In other words:
//this is working when adding property to message in the device code
temperature > 30
//this is not working when message contains json object without using any properties
$body.temperature > 30
Do we still need to use the message properties?

This feature (such as a filtering on the $body) requires setup the following message system properties:
message.ContentType = "application/json";
message.ContentEncoding = "utf-8";
See more details here.

Related

Kotlin for Volley, how can I check the JSON request for newer data in the API?

I'm working on an app that gets a list of documents/source URL from an api. I'd like to periodically check for new or updated contents within that API so users can update saved items in the database. I'm at a loss on the correct wording to search, thus Google and Stack Overflow have both failed me. My fetching function is below:
The URL for the API is https://api.afiexplorer.com
private fun fetchPubs() {
_binding.contentMain.loading.visibility = View.VISIBLE
request = JsonArrayRequest(
Request.Method.GET,
Config.BASE_URL,
JSONArray(),{ response ->
val items: List<Pubs> =
Gson().fromJson(response.toString(), object : TypeToken<List<Pubs>>() {}.type)
val sortedItems = items.sortedWith(compareBy { it.Number })
pubsList?.clear()
pubsList?.addAll(sortedItems)
// Hardcoded pubs moved to Publications Gitlab Repo
// https://gitlab.com/afi-explorer/pubs
_binding.contentMain.recyclerView.recycledViewPool.clear()
adapter?.notifyDataSetChanged()
_binding.contentMain.loading.visibility = View.GONE
setupData()
Log.i("LENGTH OF DATA", "${items.size}")
},
{error ->
println(error.printStackTrace())
Toasty.error(applicationContext, getString(string.no_internet), Toast.LENGTH_SHORT, true).show()
}
)
MyApplication.instance.addToRequestQueue(request!!)
}
private fun setupData(){
adapter = MainAdapter(applicationContext, pubsList!!, this)
_binding.contentMain.recyclerView.adapter = adapter
}
I tried using ChatGPT to see if that would get me started and that failed miserably. Also searched Google, Reddit and Stack Overflow for similar projects, but mine is a unique scenario I guess. I'm just a hobbyist and intermediate dev I guess. First time working with Volley, everything works, but I would like to find a way to send a notification (preferably not Firebase) if there is updated info within the API listed above. I'm not sure if this is actually doable.
Are you asking if you can somehow find if the remote API has changed its content? If so, how would that service advise you? If the service provider provides a web hook or similar callback you could write a server-based program to send a push notification to your Android app.
Perhaps you intent to poll the API periodically, and then you want to know if there is a change?
If you use a tool such as Postman or curl to easily see the headers of the API https://api.afiexplorer.com you will see, unfortunately, there is no Last-Modified header or ETag header which would allow you to easily determine if there was a change.
Next looking at the content of the API, the author does not provide an obvious version/change date, so no luck there.
What you could do is receive the content as a String, and perform a checksum operation on it, and if it differs you know there has been a change
or if you are deserialising the received JSON in Kotlin data classes, then out of the box, Kotlin will enable you to perform an equality operation on a previous copy of the data to know if there was a change.
This looks like an android app; if so, why don't you create a background service that makes requests to the API and updates the data as needed? You can use an AlarmManager class to set the interval threshold for polling by using the setInexactRepeating() method.
Most apps are updated in this fashion; sometimes, a separate table is created to catalog changesets.
Let me know if this helps.

How to include information about iotEdge capability in device created event in IoT Hub?

I am wondering if it is possible to include information if device is an edge device in Microsoft.Devices.DeviceCreated event data? I receive those events for both type of devices but I am not able to distinguish them and say oh yeah this one is an edge device.
I can see that device twin which I receive is a little bit different than the one I can see in portal. In portal twin contains information about capabilities which say iotEdge: true for edge and false for directly connected devices.
Basically, there are two ways to handle this issue:
The subscriber event handler (EventGridTrigger function) will pull up the full device twins info like you can see on the portal.
Using the Bulk Create or Update REST API call for creating devices with an additional information in the tags. I do recommend this way and based on my answer here, the following is an example of the payload POST:
[
{
"id":"TD_0001",
"importMode":"create",
"status":"enabled",
"tags":{
"capabilities":{
"iotEdge":false
}
}
},
{
"id":"TD_0002",
"importMode":"create",
"status":"enabled",
"tags":{
"capabilities":{
"iotEdge":true
}
},
"capabilities":{
"iotEdge":true
}
}
]
As you can see, the capabilities property has been added in the tags. Basically, you can initialized any device twins properties included a reported property.
The Azure IoT Hub Notification to the AEG is almost immediately and the following screen snippet shows an example of the event message:
and the azure portal screen:

How to access SAP OData messages in Kapsel offline app?

We are developing an SAP Fiori App to be used on the Launchpad and as an offline-enabled hybrid app as well using the SAP SDK and its Kapsel Plug Ins. One issue we are facing at the moment is the ODATA message handling.
On the Gateway, we are using the Message Manager to add additional information to the response
" ABAP snippet, random Gateway entity method
[...]
DATA(lo_message_container) = me->mo_context->get_message_container( ).
lo_message_container->add_message(
iv_msg_type = /iwbep/cl_cos_logger=>warning
iv_msg_number = '123'
iv_msg_id = 'ZFOO'
).
" optional, only used for 'true' errors
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_message_container.
In the Fiori app, we can directly access those data from the message manager. The data can be applied to a MessageView control.
// Fiori part (Desktop, online)
var aMessageData = sap.ui.getCore().getMessageManager().getMessageModel().getData();
However, our offline app always has an empty message model. After a sync or flush, the message model is always empty - even after triggering message generating methods in the backend.
The only way to get some kind of messages is to raise a /iwbep/cx_mgw_busi_exception and pass the message container. The messages can be found, in an unparsed state, in the /ErrorArchive entity and be read for further use.
// Hybrid App part, offline, after sync and flush
this.getModel().read("/ErrorArchive", { success: .... })
This approach limits us to negative, "exception worthy", messages only. We also have to code some parts of our app twice (Desktop vs. Offlne App).
So: Is there a "proper" to access those messages after an offline sync and flush?
For analyzing the issue, you might use the tool ILOData as seen in this blog:
Step by Step with the SAP Cloud Platform SDK for Android — Part 6c — Using ILOData
Note, ILOData is part of the Kapsel SDK, so while the blog above was part of a series on the SAP Cloud Platform SDK for Android, it also applies to Kapsel apps.
ILOData is a command line based tool that lets you execute OData requests and queries against an offline store.
It functions as an offline OData client, without the need for an application.
Therefore, it’s a good tool to use to test data from the backend system, as well as verify app behavior.
If a client has a problem with some entries on their device, the offline store from the device can be retrieved using the sendStore method and then ILOData can be used to query the database.
This blog about Kapsel Offline OData plugin might also be helpful.

DeviceClient.GetTwinAsync() returns null?

I've created an IotHub, added a device, created a UWP app which uses the DeviceClient to successfully connect to the hub.
I can send telemetry as expected, and see the results in the Device Explorer.
However, when I try to fetch the device twin, I'm returned a null.
var deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Amqp);
var twin = await deviceClient.GetTwinAsync(); // <<<< returns null
Are there any common scenarios that might cause this? Such as creating the IoTHub & device before Twin's were released. Or, not having set any desired properties before hand? Or, using the wrong shared access key? (etc.)
-John
SOLUTION: Twin capabilities requires the MQTT protocol, I was using AMQP.
I'm sure there is a mention of this buried somewhere, but after spinning on this for hours I can safely say it wasn't obvious.
On a more practical note: it would probably be helpful to throw an exception in the GetTwinAsync() method, if it is called on a connection that is not capable of supporting Twin.
Hopefully this post will help the next person.
-John

Bind Broadcast function return 500 without any error meesage when binding "Stream now" broadcast ID

I tried use YouTube livestream API to stream from my camera to Stream Now feature. I was able to retrieve the ID of "Stream Now" broadcast ID via the list/ API of broadcast: https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/list
However when I tried to bind this broadcast ID using bind API/, either I was using streamID or not using streamID, I still receive 500 response without any detail from YouTube.
500 is an internal server error. Without an error message or stack trace, it will be difficult to tell what went wrong.
If you're using the "Stream Now" feature, it's possible that your liveEvent and your liveBroadcast objects have already been bound together. If that is the case, you could hit the liveBroadcasts/bind endpoint with an empty streamId parameter to remove any existing bindings between the broadcast and a video stream. Then you could call /bind again with a newly created stream to restore the video content.