I'm working on connecting sensors to a FIWARE system.
The sensor can report the monitoring data with MQTT in json payload.
With a public mqtt broker(hivemq), I can get the monitoring data payload as below:
{
"src":"shellyplus1pm-7c87ce64d540",
"dst":"shellyplus1pm-7c87ce64d540/events",
"method":"NotifyStatus",
"params":{
"ts":1659606613.35,
"switch:0":{
"id":0,
"apower":38.04
}
}
}.
my questions are:
(1) the sensor can only publish data on topic DeviceId/events/rpc, but if I use FIWARE IotAgent-json, the IotAgent-json expects subscribing data on topic /json/{{api-key}}/{{device-id}}/attrs (according https://github.com/yanpengwuIoT/tutorials.IoT-over-MQTT), how can I let the IotAgent-json subscribe data on topic DeviceId/events/rpc, which is sensor firmware defined and can't be changed.
(2) the sensor publishs monitoring payload as a nested multi-level json object as showed above, but the IotAgent-json can only support a single level json object (like '{"h": 70, "t": 15}' as described in https://github.com/telefonicaid/iotagent-json/blob/master/docs/usermanual.md), how can I parse the multi-level json object in IotAgent-json?
Any comment, sample or documentation for this are very appreciated! Thank you very much.
You can create a small relay middleware to read from one topic and write to another:
const mqtt = require('mqtt');
const MQTT_BROKER_URL = process.env.MQTT_BROKER_URL || 'mqtt://mosquitto';
const MQTT_TOPIC_PROTOCOL = process.env.MQTT_TOPIC_PROTOCOL || 'json';
global.MQTT_CLIENT = mqtt.connect(MQTT_BROKER_URL);
MQTT_CLIENT.on('connect', () => {
MQTT_CLIENT.subscribe('/+/events/rpc');
});
MQTT_CLIENT.on('message', measureReceived);
function measureReceived(topic, message) {
const parts = topic.toString().split('/');
// Extract the deviceId
const deviceId = parts[2];
// Muck around with the payload and use the right topic
const apiKey = 'XXX'
process.nextTick(() => {relay(apiKey, deviceId, newPayload, newTopic)});
}
function relay(apiKey, deviceId, state, topic) {
let mqttTopic = '/' + apiKey + '/' + deviceId + '/' + topic;
MQTT_CLIENT.publish(mqttTopic, state);
}
You could hard-code the logic to unpack the incoming complex measure and a create a simpler payload, or you could investigate the use of the IoT Agent's expression library and provision the device so that it cherry picks the correct parts of the payload. Doing this is more sustainable in the long run, but would require knowledge of the JEXL expression language
Related
First timer when it comes to connecting to API. I'm trying to pull data from Toggl using my API token but I can't get credentials working. I tried to replicate the method by Chris Webb (https://blog.crossjoin.co.uk/2014/03/26/working-with-web-services-in-power-query/) but I can't get it working. Here's my M code:
let
Source = Web.Contents(
"https://toggl.com/reports/api/v2/details?workspace_id=xxxxx&client=xxxxxx6&billable=yes&user_agent=xxxxxxx",
[
Query=[ #"filter"="", #"orderBy"=""],
ApiKeyName="api-token"
])
in
Source
After that I'm inputting my API Token into Web API method in Access Web content windows but I get an error that credentials could not be authenticated. Here's Toggl API specification:
https://github.com/toggl/toggl_api_docs/blob/master/reports.md
Web.Contents function receives two parameters: url + options
Inside options, you define the headers and the api_key, and other queryable properties, such as:
let
baseUrl = "https://toggl.com/",
// the token part can vary depending on the requisites of the API
accessToken = "Bearer" & "insert api token here"
options = [
Headers = [Authorization = accessToken, #"Content-Type" =
"application/Json"], RelativePath ="reports/api/v2/details", Query =
[workspace_id=xxxxx, client=xxxxxx6 , billable=yes, user_agent=xxxxxxx]
]
Source = Web.Contents(baseUrl, options)
// since Web.Contents() doesn't parse the binaries it fetches, you must use another
// function to see if the data was retreived, based on the datatype of the data
parsedData = Json.Document(Source)
in
parsedData
The baseUrl is the smallest url that works and never changes;
The RelativePath is the next part of the url before the first "?".
The Query record is where you define all the attributes to query as a record.
This is usually the format, but check the documentation of the API you're querying to see if it is similar.
I am trying to do webhook fulfillment for my dialogflow agent. However there are four specific intents that should all have different JSON responses based on what specific intent is called. Right now I am creating a switch case based on the called intent's displayName. However that is not working. Should I be using a different parameter to check what intent is called other than displayName?
HERE IS MY CODE THAT ONLY OUTPUTS "test"
server.post("/get-bill-details", function(req, res) {
let intentName = req.body.queryResult.intent.displayName;
let ret = "test";
if(intentName == "1 - Bill"){
ret = "your billing amount is $120.";
}
return res.json({
fulfillmentText: ret,
source: "get-bill-details"
});
});
I would suggest you use client libraries as they will ease out the process of parsing the JSON and reduce your development time. You can use NodeJS or Python clients for Dialogflow. Also, if you need Google Assistant, you can also use following NodeJS library to build webhook. They all have documentation on how to build webhooks on cloud or by using Express and other frameworks.
Instead of matching with intent name give your intent an action name( try not to give any spaces e.g input.welcome ).
Then get the action parameter using
let action = req.body.queryResult.action;
switch(action) {
your logic..
}
Also as abhinav said you can use this library to ease your development time and better readability of your code that also help cross platform response for Cards, Image and Suggestions.
const { WebhookClient } = require('dialogflow-fulfillment');
server.post('/', function (request, response, next) {
const agent = new WebhookClient({ request, response });
const welcome = () => {
agent.add('Hello Welcome To My bot');
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
agent.handleRequest(intentMap);
}
I am using Pre Token Generation to update the claims of IdToken.
I am successfully able to update claim using single key:value pair.
Below is the sample example of that.
event["response"] = {"claimsOverrideDetails":{"claimsToAddOrOverride":{"scope": "test.debug"}}}
But when i am trying to add array of string inside that, it giving me internal server error (Response from AWS Cognito)
Ex:
event["response"] = {"claimsOverrideDetails":{"claimsToAddOrOverride":{"scope": ["test1","test2]}}}
It is working fine using 'Test' option of lambda function.
If i am using groupsToOverride then it is overriding the cognito:groups claim.
Any help?
I think this must be a bug with Cognito and unfortunately will require a workaround until it's resolved.
It's not ideal I know, but I've worked around this issue by using a delimited string which I then parse to an array when I receive the token.
Lambda:
exports.handler = (event, context, callback) => {
event.response = {
"claimsOverrideDetails": {
"claimsToAddOrOverride": {
"scope": "test1|test2"
}
}
};
// Return to Amazon Cognito
callback(null, event);
};
Client:
const token = jwt.decode(id_token);
const scopes = token.scope.split('|');
The name scope have special meaning in a JWT, libraries expect this to be a list in string form separated by space. So the scopes test1 and test2 would become "test1 test2".
I would recommend using space as separator and not any other format. If you prefer another format just give your field a different name - like group.
{
"iss": "https://authorization-server.example.com/",
"sub": " 5ba552d67",
"aud": "https://rs.example.com/",
"exp": 1544645174,
"client_id": "s6BhdRkqt3_",
"scope": "openid profile reademail"
}
I've the following code that returns json object. And I need to filter sender email, subject, and creationDate. The code does the job but I felt like there is an efficient way to do it. I appreciate your suggestion.
ResponseEntity<String> response =
restTemplate.exchange(app.getResourceUrl() + personnelEmail+
MESSAGE+"/?$select=Sender,Subject,CreatedDateTime", HttpMethod.GET, request, String.class);
String str=response.getBody();
JSONObject jsonObject= new JSONObject(str);
JSONArray arrayList= (JSONArray)jsonObject.get("value");
List l=arrayList.toList();
for(int i=0;i<l.size();i++){
HashMap<String,HashMap> hashMap=(HashMap<String,HashMap>)l.get(i);
HashMap<String,HashMap> sender= hashMap.get("sender");
HashMap<String,String> senderEmail= sender.get("emailAddress");
String email= senderEmail.get("address");
}
Here is the json object I receive from MS Office API.
{"#odata.context":"https://graph.microsoft.com/v1.0/$metadata#users('user34.onmicrosoft.com')/messages(sender,subject,createdDateTime)","value":[{"#odata.etag":"W/\”sljkasfdiou7978klosadf\"","id”:"lkjasdfu97978KLJASDFS_WGHJJ76J897DKdcuvtymBTItq836K34PUAAAvoK3SAAA=","createdDateTime":"2016-08-27T04:07:08Z","subject":"View
your Office 365 Enterprise E3 billing
statement","sender":{"emailAddress":{"name":"Microsoft Online Services
Team","address”:"T45763#email.microsoftonline.com"}}},{"#odata.etag":"W/\”JUU70303\"","id”:”UEYO93988FK;O38GV3J884=","createdDateTime":"2016-08-26T15:28:47Z","subject":"Order
confirmation: Thank you for your
purchase","sender":{"emailAddress":{"name":"Microsoft Online Services
Team","address":"obue733#email.microsoftonline.com"}}},{"#odata.etag":"W/\”LJKOIU987983\"","id”:”ladjksflk83l.x8783LKFW3=","createdDateTime":"2016-06-24T03:03:26Z","subject":"Attention:
Your Microsoft Azure Active Directory Premium trial subscription will
be disabled soon","sender":{"emailAddress":{"name":"Microsoft Online
Services Team","address":"635cdeee#email.microsoftonline.com"}}}]}
By default Office 365 REST API response payload also includes common annotations such as:
odata.context: the context URL of the payload
odata.etag: the ETag of the entity, as appropriate
The below picture demonstrates it
As you've already might guessed it could be controlled via odata.metadata parameter:
The odata.metadata parameter can be applied to the Accept header of
an OData request to influence how much control information will be
included in the response.
Example (C# version)
The example demonstrates how to set odata.metadata=none format parameter via Accept header to indicate that the service SHOULD omit control information
using (var client = new HttpClient(handler))
{
var url = "https://outlook.office365.com/api/v1.0/me/messages?$select=Sender,Subject,DateTimeCreated";
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(GetMediaType("none",false,false)));
var result = await client.GetStringAsync(url);
var data = JObject.Parse(result);
foreach (var item in data["value"])
{
//process item;
}
}
where
private static string GetMediaType(string metadata,bool streaming,bool IEEE754Compatible)
{
return String.Format("application/json; OData.metadata={0}; OData.streaming={1}; IEEE754Compatible={2}",metadata,streaming, IEEE754Compatible);
}
Could I send a request GET to a restful server,that contain a JSON object ?
In case that I can, how can I get it from server side ?
Thanks in advance
Most restful servers working with data in JSON format (if not in parameter, or XML format). You can take a look at the example at the jQuery page. You can also call publicly available services such as Google weather service.
Example of AJAX call with using the JSON data:
var data = { name: "John", time: "2pm" };
$.getJSON( "test.js", data )
.done(function( json ) {
console.log( "JSON Data: " + json.users[1].name );
})