Passing attribute from AWS Connect to Lambda using Python - python-3.x

Stuck on a single step and doc searching isn't helping...
In Connect I have:
Store customer input : "What's your age?"
Set contact attribute: age -> system -> stored customer input
I know the above works because I've had a Play Prompt read back the attribute.
I want Lambda to handle somethings with the age. I setup a function, I attached it to the Connect instance. I added it to the flow with a simple value pair response and that works (the Play Prompt plays back the non-dynamic response from Lambda).
When I try to make it dynamic breaks.
My understanding is that I should be able to get to this attribute in Lambda by using the passed JSON.... so I'm doing this:
age = event["Details"]["ContactData"]["Attributes"]["age"]
Connect starts saying it has trouble accessing the attribute and ends the call. What am I doing wrong? The rest of the Python code is fine because if I hard set age (age = 24) the code runs fine.

There was nothing wrong my code as it pertains to the lambda / connect integration... it was with something that was just causing an error. I started monitoring the function in cloudwatch and that helped!

Related

Read variables value from PLC with Python opcua-asyncio – BadNoMatch: “The requested operation has no match to return.”

Edited to correct some typos:
Hi I’m new to opcua-asyncio package so please be patient if I missed something really obvious, I’m trying to figure out how to connect to a Siemens S7 1200 CPU 1212C firmware version 14 PLC from Python (3.11) and read some variables values.
I’m sorry I can’t figure out a way to support my case with a reproducible example because it’s intrinsically connected to the test PLC I’m working with, if you can suggest a way to make it reproducible I’m going to amend the answer accordingly.
The structure on my test PLC is detailed in the picture, I can access it through different clients, the variables from t1 to t19 are my goal.
[PLC Structure][1]
I went through the documentation (especially the client minimal example ) and some stackoverflow answers and I wrote the following code
# modules
import asyncio
from asyncua import Client
# url and namespace
url = foo bar # the plc location on the network
namespace = "OPC-UA:PLC_1"
t2 =[]
# I can find the objects inside the node
async with Client(url=url) as client:
# Find the namespace index
nsidx = await client.get_namespace_index("urn:OPC-UA:PLC_1")
print(nsidx)
root = client.nodes.root
print("Root node is: ", root)
objects = client.nodes.objects
print("Objects node is: ", objects)
# I can’t find my variables
var = await client.nodes.root.get_child(
["0:Objects", "3:ServerInterfaces", "0:Face"])
print("Var is: ", var)
t2 = await var.get_children_descriptions()
print(t2)
By my understanding of the structure in OPC-UA:PLC_1 namespace I should find an “Objects” node object listing a “ServerInterfaces” node object listing a “Face” node object listing the variables from t1 to t19. However if I ask “Objects” to describe its childs through get_children_descriptions() I can see the ServerInterfaces node object however this Serverinterfaces appears to be named “Face”.
If I ask for the childrens of “Face” I receive a BadNoMatch error.
Any help pointing me to the right direction would be much appreciated. Thank you!
[1]: https://i.stack.imgur.com/QyQCJ.png
I think the Browsename namespace index of Face is wrong.
The index 0 is used for the base nodeset.
You can check the correct index with an other UA Client like the UAExpert (here you need to look at the attibute window not the address space window (which do not show the namespace index)).
If you defined the Face in the face "OPC-UA:PLC_1" the line should be:
var = await client.nodes.root.get_child(
["0:Objects", "3:ServerInterfaces", "3:Face"])

Problem accesing a dictionary value on dialogflow fullfilment

I am using fullfilment section on dialogflow on a fairly basic program I have started to show myself I can do a bigger project on dialogflow.
I have an object setup that is a dictionary.
I can make the keys a constant through
const KEYS=Object.keys(overflow);
I am going through the values using
if(KEYS.length>0){
var dictionary = overflow[keys[i]]
if I stringify dictionary using
JSON.stringify(item);
I get:
{"stack":"overflow","stack2":"overflowtoo", "stack3":3}
This leads me to believe I am actually facing a dictionary, hence the name of the variable.
I am accesing a string variable such as stack and unlike stack3
Everything I have read online tells me
dictionary.stack
Should work since
JSON.stringify(item);
Shows me:
{"stack":"overflow","stack2":"overflowtoo","stack3":3}
Whenever I:
Try to add the variable to the response string.
Append it to a string using output+=${item.tipo};
I get an error that the function crashed. I can replace it with the stringify line and it works and it gives me the JSON provided so the issue isnt there
Dictionary values are created as such before being accessed on another function:
dictionary[request.body.responseId]={
"stack":"overflow",
"stack2":"overflowtoo",
"stack3":3 };
Based on the suggestion here I saw that the properties where being accessed properly but their type was undefined. Going over things repeatedly I saw that the properties where defined as list rather than single values.
Dot notation works when they stop being lists.
Thanks for guiding me towards the problem.

Invoke autoscript (has WO object launch point) when Service Address is updated?

I have a WO in Maximo 7.6.1.1.
When a user updates the Service Address, I want to invoke an autoscript that has an Object Launch Point on the WORKORDER object.
Is there a way to invoke an autoscript (that has an object launch point on the WORKORDER object) when the Service Address is updated?
You should see if mbo.getOwner() returns something and if that something.getName() is WORKORDER and, further, the work order you are expecting it to be. Subject to all that, you can invoke that other autoscript with code like this:
from java.util import HashMap
lpVars = HashMap()
lpVars.put("mbo",mbo.getOwner())
#repeat the last line for any other implicit/explicit variables your target
#script is going to use / expect to be defined
service.invokeScript("YOURSCRIPTNAME", lpVars)
someVar = lpVars.get("someVarDefinedInYOURSCRIPTNAMEWhenItEnded")
Note the work with the lpVars variable. I use it to store the "implicit"/"explicit" variables (e.g. "mbo") that the script I'm calling will expect to be defined. Basically, I'm doing the setup a launch point normally does, since my code is the launch point. Then, since I'm the launch point, I have access to whatever variables were defined when the script ended by Maximo adding them to / updating them in lpVars.
You can create reusable "library" scripts that you can call directly as Preacher explained. See IBM example here: https://www.ibm.com/support/knowledgecenter/SSFGJ4_7.6.0/com.ibm.mbs.doc/autoscript/c_example_reuse.html
So you could have your WO object launchpoint call the library script and your SA object launchpoint calling the same. You then just need to make change to one script if needed and that's great.
I don't believe you can. An object launch point is all about telling Maximo which object to monitor for the following event(s), not exactly about which object to launch the script on (though, for various reasons, those two are necessarily tied together).
What you can do, though, is put your launch point on the service address as you really do want, but then in your script fetch the on-screen/in-memory work order that you want to do something with and do that. This is done through the getOwner() method call or the special ":owner" (maybe with the ampersands, I can't remember) relationship reference.
This is the solution I came up with:
mboName=mbo.getName()
if mboName == 'WOSERVICEADDRESS':
mboWO = mbo.getOwner()
elif mboName == 'WORKORDER':
mboWO=mbo
sax = mboWO.getDouble("SERVICEADDRESS.LONGITUDEX")
say = mboWO.getDouble("SERVICEADDRESS.LATITUDEY")
if sax and say:
mboWO.setValue("longitudex", sax)
mboWO.setValue("latitudey", say)
elif mboWO.getString("ASSETNUM") and mboWO.getBoolean("ASSET.PLUSSISGIS") == 1:
mboWO.setValue("longitudex", mboWO.getDouble("ASSET.longitudex"))
mboWO.setValue("latitudey", mboWO.getDouble("ASSET.latitudey"))
elif mboWO.getString("LOCATION") and mboWO.getBoolean("LOCATION.PLUSSISGIS") == 1:
mboWO.setValue("longitudex", mboWO.getDouble("LOCATION.longitudex"))
mboWO.setValue("latitudey", mboWO.getDouble("LOCATION.latitudey"))
else:
mboWO.setValue("longitudex", None)
mboWO.setValue("latitudey", None)
The script has launch points on multiple objects:

ScriptError using Google Apps Script Execution API

Following these guides https://developers.google.com/apps-script/guides/rest/quickstart/target-script and https://developers.google.com/apps-script/guides/rest/quickstart/nodejs, I am trying to use the Execution API in node to return some data that are in a Google Spreadsheet.
I have set the script ID to be the Project Key of the Apps Script file. I have also verified that running the function in the Script Editor works successfully.
However, when running the script locally with node, I get this error:
The API returned an error: Error: ScriptError
I have also made sure the script is associated with the project that I use to auth with Google APIs as well.
Does anyone have any suggestion on what I can do to debug/ fix this issue? The error is so generic that I am not sure where to look.
UPDATE: I've included a copy of the code in this JSBin (the year function is the entry point)
https://jsbin.com/zanefitasi/edit?js
UPDATE 2: The error seems to be caused by the inclusion of this line
var spreadsheet = SpreadsheetApp.open(DriveApp.getFileById(docID));
It seems that I didn't request the right scopes. The nodejs example include 'https://www.googleapis.com/auth/drive', but I also needed to include 'https://www.googleapis.com/auth/spreadsheets' in the SCOPES array. It seems like the error message ScriptError is not very informative here.
In order to find what scopes you'd need, to go the Script Editor > File > Project Properties > Scopes. Remember to delete the old credentials ~/.credentials/old-credential.json so that the script will request a new one.
EDIT: With the update in information I took a closer look and saw you are returning a non-basic type. Specifically you are returning a Sheet Object.
The basic types in Apps Script are similar to the basic types in
JavaScript: strings, arrays, objects, numbers and booleans. The
Execution API can only take and return values corresponding to these
basic types -- more complex Apps Script objects (like a Document or
Sheet) cannot be passed by the API.
https://developers.google.com/apps-script/guides/rest/api
In your Account "Class"
this.report = spreadsheet.getSheetByName(data.reportSheet);
old answer:
'data.business_exp' will be null in this context. You need to load the data from somewhere. Every time a script is called a new instance of the script is created. At the end of execution chain it will be destroyed. Any data stored as global objects will be lost. You need to save that data to a permanent location such as the script/user properties, and reloaded on each script execution.
https://developers.google.com/apps-script/reference/properties/

GXT LiveGrid set default status string before and after loading the data through RPC call

I am using a liveGrid to load the data dymaically from the server.
The code is working fine. Now, I need to do a small enhancement in that, and for that I need some advice.
I need to display, a generic string like "Loading...", before the data gets populated from the server.
This can be done as following :-
LiveGridView liveView = new LiveGridView();
liveView.setEmptyText("Loading...");
Now, once the RPC call returns, I get my data, and I set the same in the live Grid and that works fine.
But when I dont get any data from the RPC call, I need to change that "Loading..." string to a new string like "No data available on the server". So, how can I do that?
Thanks in advance.
Regards
Ajay
I got the solution for this.
After the data is loaded, we can add a Loader.Load listner on the loader, and check the Length of the result. If it equals zero, then change the LiveGridView's emptyText value.
Thanks
Ajay

Resources