Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[smach_to_mail] Add NOTIFICATION_LEVEL #1648

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jsk_robot_common/jsk_robot_startup/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ generate_dynamic_reconfigure_options(
cfg/OdometryFeedbackWrapperReconfigure.cfg
cfg/ConstantHeightFramePublisherReconfigure.cfg
cfg/JointStatesThrottle.cfg
cfg/SmachNotificationLevel.cfg
)

add_message_files(
Expand Down
2 changes: 1 addition & 1 deletion jsk_robot_common/jsk_robot_startup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ flowchart TB
id1 --> tweet[[pub /tweet std_msgs::String]]
id1 --> chat[[pub /google_chat_ros/send/goal<br>google_chat_ros::SendMessageAction]]
end
S -->|"[{'DESCRIPTION': string, 'IMAGE': base64}]"| E
S -->|"[{'DESCRIPTION': string, 'IMAGE': base64, 'NOTIFICATION_LEVEL': enum}]"| E
email --> email_body(["DESCRIPTION[0]<br>DESCRIPTION[1]<br>IMAGE[1]<br>DESCRIPTION[1]<br>IMAGE[1]<br>..."])
tweet --> tweet_body1(["DESCRIPTION[0]"])
tweet_body1 --> tweet_body2(["DESCRIPTION[1]<br>IMAGE[1]"])
Expand Down
21 changes: 21 additions & 0 deletions jsk_robot_common/jsk_robot_startup/cfg/SmachNotificationLevel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python

from dynamic_reconfigure.parameter_generator_catkin import *

PKG = "jsk_robot_startup"

gen = ParameterGenerator()

notification_level_enum = gen.enum([
gen.const("DEBUG", int_t, 0, "Debug level"),
gen.const("INFO", int_t, 1, "Info level"),
gen.const("NOTICE", int_t, 2, "Notice level"),
gen.const("CRITICAL", int_t, 3, "Critical level"),
gen.const("EMERGENCY", int_t, 4, "Emergency level")],
"An enum to set notification level")

gen.add("email_level", int_t, 0, "Email notification level", 1, 0, 4, edit_method=notification_level_enum)
gen.add("twitter_level", int_t, 0, "Twitter notification level", 1, 0, 4, edit_method=notification_level_enum)
gen.add("chat_level", int_t, 0, "Chat notification level", 2, 0, 4, edit_method=notification_level_enum)

exit(gen.generate(PKG, PKG, "SmachNotificationLevel"))
118 changes: 75 additions & 43 deletions jsk_robot_common/jsk_robot_startup/scripts/smach_to_mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,30 @@
import datetime
import pickle
import rospy
import os
import sys

from cv_bridge import CvBridge
from dynamic_reconfigure.server import Server
from google_chat_ros.msg import Card
from google_chat_ros.msg import Section
from google_chat_ros.msg import SendMessageAction
from google_chat_ros.msg import SendMessageActionGoal
from google_chat_ros.msg import WidgetMarkup
from jsk_robot_startup.cfg import SmachNotificationLevelConfig as Config
from jsk_robot_startup.msg import Email
from jsk_robot_startup.msg import EmailBody
from sensor_msgs.msg import CompressedImage
from smach_msgs.msg import SmachContainerStatus
from std_msgs.msg import String

NOTIFICATION_LEVELS = {
"DEBUG": 0,
"INFO": 1,
"NOTICE": 2,
"CRITICAL": 3,
"EMERGENCY": 4
}

class SmachToMail():

Expand All @@ -30,6 +40,11 @@ def __init__(self):
self.use_mail = rospy.get_param("~use_mail", True)
self.use_twitter = rospy.get_param("~use_twitter", True)
self.use_google_chat = rospy.get_param("~use_google_chat", True)
# Dynamic Reconfigure
self.reconfigure_srv = Server(Config, self.reconfigure_cb)
self.email_level = Config.SmachNotificationLevel_INFO
self.twitter_level = Config.SmachNotificationLevel_INFO
self.chat_level = Config.SmachNotificationLevel_NOTICE
self.pub_email = rospy.Publisher("email", Email, queue_size=10)
self.pub_twitter = rospy.Publisher("tweet", String, queue_size=10)
rospy.Subscriber(
Expand All @@ -53,6 +68,12 @@ def __init__(self):
self.gchat_image_dir = rospy.get_param("~google_chat_tmp_image_dir", "/tmp")
self._gchat_thread = None

def reconfigure_cb(self, config, level):
self.email_level = config.email_level
self.twitter_level = config.twitter_level
self.chat_level = config.chat_level
return config

def _status_cb(self, msg):
'''
Recording starts when smach_state becomes start.
Expand Down Expand Up @@ -86,6 +107,8 @@ def _status_cb(self, msg):
rospy.loginfo("- info_str -> {}".format(local_data_str['INFO']))
else:
rospy.logwarn("smach does not have INFO, see https://github.com/jsk-ros-pkg/jsk_robot/tree/master/jsk_robot_common/jsk_robot_startup#smach_to_mailpy for more info")
if 'NOTIFICATION-LEVEL' in local_data_str:
rospy.loginfo("- notification_level -> {}".format(local_data_str['NOTIFICATION_LEVEL']))


# Store data for every callerid to self.smach_state_list[caller_id]
Expand All @@ -102,7 +125,7 @@ def _status_cb(self, msg):
self.smach_state_subject[caller_id] = None

# Build status_dict for every status
# expected keys are 'DESCRIPTION' , 'IMAGE', 'STATE', 'INFO', 'TIME'
# expected keys are 'DESCRIPTION' , 'IMAGE', 'STATE', 'INFO', 'TIME', 'NOTIFICATION_LEVEL'
status_dict = {}
if 'DESCRIPTION' in local_data_str:
status_dict.update({'DESCRIPTION': local_data_str['DESCRIPTION']})
Expand All @@ -120,6 +143,12 @@ def _status_cb(self, msg):
status_dict.update({'STATE': status_str})
status_dict.update({'INFO': info_str})
status_dict.update({'TIME': datetime.datetime.fromtimestamp(msg.header.stamp.to_sec())})
if ('NOTIFICATION_LEVEL' in local_data_str) and (local_data_str['NOTIFICATION_LEVEL'] in NOTIFICATION_LEVELS.keys()):
status_dict.update({'NOTIFICATION_LEVEL': NOTIFICATION_LEVELS[local_data_str['NOTIFICATION_LEVEL']]})
else:
# set notification_level INFO by default
rospy.loginfo("Notification level is not set or invalid. Set INFO by default")
status_dict.update({'NOTIFICATION_LEVEL': NOTIFICATION_LEVELS["INFO"]})


if (caller_id not in self.smach_state_list) or self.smach_state_list[caller_id] is None:
Expand Down Expand Up @@ -156,19 +185,20 @@ def _send_mail(self, subject, state_list):
separator.type = 'text'
separator.message = "---------------"
for x in state_list:
if 'DESCRIPTION' in x:
description = EmailBody()
description.type = 'text'
description.message = x['DESCRIPTION']
email_msg.body.append(description)
email_msg.body.append(changeline)
if 'IMAGE' in x and x['IMAGE']:
image = EmailBody()
image.type = 'img'
image.img_size = 100
image.img_data = x['IMAGE']
email_msg.body.append(image)
email_msg.body.append(changeline)
if x["NOTIFICATION_LEVEL"] >= self.email_level:
if 'DESCRIPTION' in x:
description = EmailBody()
description.type = 'text'
description.message = x['DESCRIPTION']
email_msg.body.append(description)
email_msg.body.append(changeline)
if 'IMAGE' in x and x['IMAGE']:
image = EmailBody()
image.type = 'img'
image.img_size = 100
image.img_data = x['IMAGE']
email_msg.body.append(image)
email_msg.body.append(changeline)
email_msg.body.append(changeline)
email_msg.body.append(changeline)
email_msg.body.append(separator)
Expand Down Expand Up @@ -203,22 +233,23 @@ def _send_twitter(self, subject, state_list):
text += subject
prev_text_type = ''
for x in state_list:
if 'DESCRIPTION' in x and x['DESCRIPTION']:
desc = x['DESCRIPTION']
if isinstance(desc, bytes):
desc = desc.decode('utf-8')
text += '\n' + desc
prev_text_type = 'DESCRIPTION'
if 'IMAGE' in x and x['IMAGE']:
img_txt = x['IMAGE']
if isinstance(img_txt, bytes):
img_txt = img_txt.decode('utf-8')
if prev_text_type == 'IMAGE':
# [rostwitter] Do not concatenate
# multiple base64 images without spaces.
text += ' '
text += img_txt
prev_text_type = 'IMAGE'
if x["NOTIFICATION_LEVEL"] >= self.twitter_level:
if 'DESCRIPTION' in x and x['DESCRIPTION']:
desc = x['DESCRIPTION']
if isinstance(desc, bytes):
desc = desc.decode('utf-8')
text += '\n' + desc
prev_text_type = 'DESCRIPTION'
if 'IMAGE' in x and x['IMAGE']:
img_txt = x['IMAGE']
if isinstance(img_txt, bytes):
img_txt = img_txt.decode('utf-8')
if prev_text_type == 'IMAGE':
# [rostwitter] Do not concatenate
# multiple base64 images without spaces.
text += ' '
text += img_txt
prev_text_type = 'IMAGE'
if len(text) > 1:
self.pub_twitter.publish(String(text))

Expand All @@ -229,19 +260,20 @@ def _send_google_chat(self, subject, state_list):
goal.goal.text = subject
card = Card()
for i, x in enumerate(state_list):
section = Section()
widget = WidgetMarkup()
if 'DESCRIPTION' in x:
text = x['DESCRIPTION']
section.header = text
if 'IMAGE' in x and x['IMAGE']:
path = os.path.join(self.gchat_image_dir, 'smach_gchat_{}.png'.format(i))
with open(path, "wb") as f:
f.write(base64.b64decode(x['IMAGE']))
widget.image.localpath = path
if section.header and widget.image.localpath:
section.widgets.append(widget)
card.sections.append(section)
if x["NOTIFICATION_LEVEL"] >= self.twitter_level:
section = Section()
widget = WidgetMarkup()
if 'DESCRIPTION' in x:
text = x['DESCRIPTION']
section.header = text
if 'IMAGE' in x and x['IMAGE']:
path = os.path.join(self.gchat_image_dir, 'smach_gchat_{}.png'.format(i))
with open(path, "wb") as f:
f.write(base64.b64decode(x['IMAGE']))
widget.image.localpath = path
if section.header and widget.image.localpath:
section.widgets.append(widget)
card.sections.append(section)
goal.goal.cards.append(card)
goal.goal.space = self.chat_space
if self._gchat_thread:
Expand Down