Alarm Pipeline - Notify multiple rosters dynamically

I have an application where both individual users and rosters can be assigned to a particular alarm at run time. For the individual users, I achieved this with a calculated roster that reads in my list of assigned users (a custom property on the tag) and uses the system functions to get the user objects and the contact info from the gateway for each user, then the builder to assemble the result roster.

I have a similar list of rosters, also a custom property on the tag. I want to dynamically notify any number of rosters based on that list, and also avoid duplicating notifications if a user belongs to more than one of the chosen rosters.

My first idea is to use a calculated roster again, and in scripting build the new roster by combining all the users of the individual chosen rosters and remove/avoid duplicates in that scripting. Is the the only or best way of doing this?

As I was making this post I came across this thread: Alarm Pipeline - Array of rosters showing how to loop through a list of rosters with a single notification block being called for however many rosters are in the list. This is very close to what I need, but I still think would result in the multiple notification issue?

Your idea to use a calculated roster via scripting works well. Looking at that project you shared, I agree that would result in multiple notifications.

I was able to do the merge easily in scripting,might be helpful others trying to do the same. After merging the desired rosters I can grab the contact info for each user and use the builder to generate the final roster for the notification.

Note: The function system.alarm.getRosters() is used for testing in script console, will need to change to system.roster.getRosters() when used in perspective - see note here.

# Input = List of roster names to merge
# Returns = List of users contained by these rosters, without duplicates.
def mergeRosters(rosters):
	users = set()
	allRosterData = system.alarm.getRosters()	# Contains rosters and each roster's users
	
	for roster in rosters:
		users = set(users+allRosterData[roster])
	
	return list(users)

# Test code...
mergedUserList = mergeRosters(["Test Roster 2", "Test Roster 3", "Maintenance"])
print mergedUserList

Hi there, i tried using this code for merging two of my rosters by creating mergeRoster() function inside project library and calling the function inside the notification block but it sends out an error requiring to return a dictionary.

Input = List of roster names to merge

Returns = Dictionary containing each user's name, email, and phone number,

without duplicates.

def mergeRosters(rosters):
users = {}
allRosterData = system.alarm.getRosters() # Contains rosters and each roster's users

for roster in rosters:
    for user in allRosterData[roster]:
        if user not in users:
            # Get the contact info for the user and add it to the dictionary
            contact_info = system.user.getContactInfo(user)
            users[user] = {
                "name": user,
                "email": contact_info.email,
                "phone_number": contact_info.phone
            }

return users

Also, I am not able to use user.getContactInfo inside the function to return the email address and the phone number. It is returning this error that i have posted below :


Can I get some help regarding this problem as well??

@Bharat_Krishnan

What are you trying to do here, looks like merge the rosters and assemble the merged version with all the contact info at the same time? In my application I first merged and ended up with a list of users, then ran through that entire list assembling the calculated roster with the contact info which might be a bit easier.

First, looking at the screenshot code which is different from your code block:

As for the error, it looks like line 17 should be should be running getContactInfo() on user_obj not user. Also this returns a sequence of contact info so more work would need to be done to pull out the email address from that sequence. It seems you've done all this in the code pasted above the screenshot.

Regarding the first code, I don't think you are re-assembling the roster correctly. See this page for some helpful examples: https://docs.inductiveautomation.com/display/DOC81/Notification+Block

I'd try returning a list of dictionaries like shown here (from example link):

Or, use the builder which was easier in my opinion:

# Specific lines taken from the examples on that page, haven't actually run this code but know this is the method I used

# This inside your loop to build each user, replacing the literal strings with your values
builder.username('john').firstname('John').lastname('Smith').email(['john@comapny.com']).phone(['1234567890']).sms(['8905671234']).add()

# Then at the end, outside of your loops
userList = builder.build()
return userList

Is it possible with my requirements? How should I edit this code to make this similar to your application? How can we get their email addresses and SMS using the contact info and builder function.

# Input = List of roster names to merge
# Returns = List of users contained by these rosters, without duplicates.
def mergeRosters(rosters):
	users = set()
	allRosterData = system.alarm.getRosters()	# Contains rosters and each roster's users
	
	for roster in rosters:
		users = set(users+allRosterData[roster])
	
	return list(users)

# Test code...
mergedUserList = mergeRosters(["TEST", "TEST2"])
print mergedUserList

the output it is returning is a unicode list and it doesnt have an attribute "get"
the output from script console : [u'bkms', u'test1']

Use the script you have there to get the list of users contained in the rosters (users in more than 1 roster are not duplicated).

From there, make another function that steps through that list getting the contact information...

# userList = Merged user list from step 1, just an exmaple here
userList = ["testUser1", "testUser2"]

for userName in userList:
	userObj = system.user.getUser("default", userName)
	contactInfo = userObj.getContactInfo()
	for contact in contactInfo:
		# Pull out email
		if contact.contactType == "email":
			currentEmail = [contact.value]
		# Have not tested but should be able to pull out phone same way
		#if contact.contactType == "phone":
		#		currentPhone = [contact.value]
	builder.username(userName).email(currentEmail).add()
	
	# If wanting phone and email
	#builder.username(userName).email(currentEmail).phone(currentPhone).add()

# Do this build right before return
calcRoster = builder.build()
return calcRoster

This is taken very closely from what I did, I added some sections you may want to add. I'm not very experienced with the builder helper to know if you can call add() multiple times per user. I'd probably try to call the builder......add() line line once per user being cautious of handling the case where a user doesn't have that type of contact where currentEmail or currentPhone variables won't get set. The builder function may not care if they are empty, not sure on that.

In my case I had 2 different notification blocks so each one independently stepped through the list pulling out the appropriate information for that notification block (so ended up with a roster of users with just emails to en email notify, another roster of users with just SMS to an SMS notify, with both notification blocks in parallel).