diff --git a/jsk_unitree_robot/jsk_unitree_startup/launch/unitree_bringup.launch b/jsk_unitree_robot/jsk_unitree_startup/launch/unitree_bringup.launch
index 6ae4f34cf1..5c3284b694 100644
--- a/jsk_unitree_robot/jsk_unitree_startup/launch/unitree_bringup.launch
+++ b/jsk_unitree_robot/jsk_unitree_startup/launch/unitree_bringup.launch
@@ -36,4 +36,9 @@
+
+
+
+
diff --git a/jsk_unitree_robot/jsk_unitree_startup/package.xml b/jsk_unitree_robot/jsk_unitree_startup/package.xml
index 000f338283..fa8a9f42ee 100644
--- a/jsk_unitree_robot/jsk_unitree_startup/package.xml
+++ b/jsk_unitree_robot/jsk_unitree_startup/package.xml
@@ -13,6 +13,7 @@
unitree_legged_real
rwt_app_chooser
app_manager
+ python3-bs4
rosserial_python
teleop_twist_joy
diff --git a/jsk_unitree_robot/jsk_unitree_startup/scripts/launch_email.py b/jsk_unitree_robot/jsk_unitree_startup/scripts/launch_email.py
new file mode 100755
index 0000000000..9dbca74fdc
--- /dev/null
+++ b/jsk_unitree_robot/jsk_unitree_startup/scripts/launch_email.py
@@ -0,0 +1,302 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import argparse
+from bs4 import BeautifulSoup
+import datetime
+import emoji
+import json
+import socket
+import sys
+import random
+import re
+import rospy
+from jsk_robot_startup.msg import Email
+from jsk_robot_startup.msg import EmailBody
+if sys.version_info.major == 2:
+ import urllib2
+else:
+ from urllib import request
+
+
+class RobotLaunchEmail:
+ """
+ Send email when robot launched with tips.
+ """
+ def __init__(self):
+ # Character code differences between python versions
+ # See https://stackoverflow.com/questions/54153986/handling-encode-when-converting-from-python2-to-python3 #NOQA
+ rospy.init_node('robot_launch_email')
+ if sys.version_info.major == 2:
+ reload(sys)
+ sys.setdefaultencoding('utf-8')
+ api_key_file = '/var/lib/robot/openweathermap_api_key.txt'
+ with open(api_key_file, 'r') as f:
+ self.appid = f.read().split('\n')[0]
+ self.constellation = "sagittarius"
+ self.constellation_jpn = "いて"
+ self.pub = rospy.Publisher("email", Email, queue_size=10)
+
+ def get_tips(self):
+ """
+ Get tips from zatsuneta random article.
+
+ Returns:
+ ----------
+ title : str
+ article title
+ contents : str
+ article contents (heading)
+ detail_url :str
+ URL of the article written about the details
+ """
+ url = 'https://zatsuneta.com/category/random.html'
+ if sys.version_info.major == 2:
+ response = urllib2.urlopen(url)
+ else:
+ response = request.urlopen(url)
+ soup = BeautifulSoup(response, 'html5lib')
+ topstories = soup.find('div', class_="article")
+ title = topstories.find('a')['title']
+ detail_url = topstories.find('a')['href']
+ contents = topstories.find('p').text
+ response.close()
+
+ return title, contents, detail_url
+
+ # Partly copied from https://github.com/knorth55/jsk_robot/blob/b2999b0cece82d7b1d46320a1e7c84e4fc078bd2/jsk_fetch_robot/jsk_fetch_startup/scripts/time_signal.py #NOQA
+ def get_weather_forecast(self, lang='en'):
+ url = 'http://api.openweathermap.org/data/2.5/weather?q=tokyo&lang={}&units=metric&appid={}'.format(lang, self.appid) # NOQA
+ if sys.version_info.major == 2:
+ resp = json.loads(urllib2.urlopen(url).read())
+ else:
+ resp = json.loads(request.urlopen(url).read())
+ weather = resp['weather'][0]['description']
+
+ forecast_text = ""
+ if lang == 'ja':
+ forecast_text = "今日の天気は" + weather + "です。"
+ else:
+ forecast_text = " The weather is " + weather + " now."
+
+ # It feels like the robot is expressing its will based on the weather.
+ if "晴" in weather:
+ forecast_tuple = (
+ '日差しに気をつけて。',
+ 'お散歩しよう!',
+ )
+ elif "雨" in weather:
+ forecast_tuple = (
+ '部屋の中で遊ぼう!',
+ '傘忘れていない?',
+ )
+ elif "雲" or "曇" or "くもり" in weather:
+ forecast_tuple = (
+ '晴れたらいいな',
+ )
+ elif "雪" in weather:
+ forecast_tuple = (
+ '雪合戦しよう!',
+ '寒さに気をつけて',
+ )
+ else:
+ forecast_tuple = (' ')
+ forecast_text += random.choice(forecast_tuple)
+
+ return forecast_text
+
+ def add_emoji(self, mode):
+ """
+ 0: 普通, 1: 喜び, 2: 安心, 3: 悪巧み, 4: 驚き, 5: 悲しみ, 6: 怒り, 7: 照れ,
+ 8: 恐怖, 9: 好き, 10: ウインク・おふざけ, 11: 退屈, 12: 混乱
+ ref: https://www.webfx.com/tools/emoji-cheat-sheet/
+ """
+ dic = {0: ":neutral_face:", 1: ":smile:", 2: ":relieved:",
+ 3: ":smirk:", 4: ":astonished:", 5: ":cry:",
+ 6: ":angry:", 7: ":flushed:", 8: ":scream:",
+ 9: ":heart_eyes:", 10: ":wink:", 11: ":sleepy:", 12: ":sweat:"}
+
+ return emoji.emojize(dic[mode], language='alias')
+
+ def set_constellation(self):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--month", default="12")
+ parser.add_argument("--days", default="14")
+ args = parser.parse_args()
+
+ birthday_num = int(args.month) * 100 + int(args.days)
+ if 1221 < birthday_num <= 1231 or 101 <= birthday_num <= 119:
+ self.constellation = "capricorn"
+ self.constellation_jpn = "やぎ"
+ elif 119 < birthday_num <= 131 or 201 <= birthday_num <= 218:
+ self.constellation = "aquarius"
+ self.constellation_jpn = "みずがめ"
+ elif 218 < birthday_num <= 229 or 301 <= birthday_num <= 320:
+ self.constellation = "pisces"
+ self.constellation_jpn = "うお"
+ elif 320 < birthday_num <= 331 or 401 <= birthday_num <= 419:
+ self.constellation = "aries"
+ self.constellation_jpn = "おひつじ"
+ elif 419 < birthday_num <= 430 or 501 <= birthday_num <= 520:
+ self.constellation = "taurus"
+ self.constellation_jpn = "おうし"
+ elif 520 < birthday_num <= 531 or 601 <= birthday_num <= 621:
+ self.constellation = "gemini"
+ self.constellation_jpn = "ふたご"
+ elif 621 < birthday_num <= 630 or 701 <= birthday_num <= 722:
+ self.constellation = "cancer"
+ self.constellation_jpn = "かに"
+ elif 722 < birthday_num <= 731 or 801 <= birthday_num <= 822:
+ self.constellation = "leo"
+ self.constellation_jpn = "しし"
+ elif 822 < birthday_num <= 831 or 901 <= birthday_num <= 922:
+ self.constellation = "virgo"
+ self.constellation_jpn = "おとめ"
+ elif 922 < birthday_num <= 930 or 1001 <= birthday_num <= 1023:
+ self.constellation = "libra"
+ self.constellation_jpn = "てんびん"
+ elif 1023 < birthday_num <= 1031 or 1101 <= birthday_num <= 1121:
+ self.constellation = "scorpio"
+ self.constellation_jpn = "さそり"
+ elif 1121 < birthday_num <= 1130 or 1201 <= birthday_num <= 1221:
+ self.constellation = "sagittarius"
+ self.constellation_jpn = "いて"
+ else:
+ rospy.logerr("Inappropriate birthday."
+ "Set default constellation: sagittarius")
+
+ def get_fortune(self):
+ """
+ Get tips from horoscope
+ Return:
+ message : str
+ """
+ def add_comment_rank(rank):
+ if rank == 1:
+ message = "すごい、1位だ" + self.add_emoji(4)
+ elif rank <= 3:
+ message = str(rank) + "位!いい感じ" + self.add_emoji(1)
+ elif rank == 12:
+ message = "最下位..."\
+ + self.add_emoji(5)\
+ + "ラッキーアイテムをチェックしなきゃ!!"
+ else:
+ message = str(rank) + "位かぁ。そこそこかな" + self.add_emoji(0)
+ return " " + message
+
+ def add_comment_love(point):
+ if point >= 9:
+ message = "出会いを求めてお散歩しちゃおっかな" + self.add_emoji(9)
+ elif point >= 6:
+ message = "気になってるあの子に会えちゃうかも" + self.add_emoji(7)
+ elif point <= 3:
+ message = "こんなの信じないぞ" + self.add_emoji(6)
+ else:
+ message = "平凡な一日になりそう..." + self.add_emoji(11)
+ return " " + message
+
+ def add_comment_money(point):
+ if point >= 9:
+ message = "今日はお買い物しちゃおうかな" + self.add_emoji(10)
+ elif point <= 3:
+ message = "お金のつかい過ぎには気をつけよう..." + self.add_emoji(8)
+ else:
+ message = "今日は何事もなさそうかな" + self.add_emoji(2)
+ return " " + message
+
+ def add_comment_business(point):
+ if point >= 7:
+ message = "研究頑張ったら良いことあるかも" + self.add_emoji(1)
+ elif point >= 4:
+ message = "いいのか悪いのか分からないなぁ" + self.add_emoji(12)
+ else:
+ message = "今日は研究さぼっちゃおうかな〜" + self.add_emoji(3)
+ return " " + message
+
+ url = 'https://fortune.yahoo.co.jp/12astro/' + self.constellation
+ if sys.version_info.major == 2:
+ response = urllib2.urlopen(url)
+ else:
+ response = request.urlopen(url)
+ soup = BeautifulSoup(response, "html.parser")
+ fortune = soup.find('div', id="jumpdtl").find_all('td')
+ f_contents = soup.find(
+ 'div', class_="yftn12a-md48").find_all('dd')[0].contents[0]
+ try:
+ rank = re.sub(
+ r"\D", "", fortune[-5].contents[0].contents[0]) + "位"
+ except BaseException:
+ rank = re.sub(
+ r"\D", "", fortune[-5].contents[0].attrs['alt']) + "位"
+ point_overall = fortune[-4].contents[0].attrs['alt']
+ point_love = fortune[-3].contents[0].attrs['alt']
+ point_money = fortune[-2].contents[0].attrs['alt']
+ point_business = fortune[-1].contents[0].attrs['alt']
+ rank_int = int(re.sub(r"\D", "", rank))
+ point_love_int = int(re.sub(r"\D", "", point_love)[2:])
+ point_money_int = int(re.sub(r"\D", "", point_money)[2:])
+ point_business_int = int(re.sub(r"\D", "", point_business)[2:])
+ message = "今日の星座占い:" + self.constellation_jpn\
+ + "座の運勢は【" + rank + "】" + add_comment_rank(rank_int) + "\n"
+ message += f_contents + "\n"
+ message += "だって!\n"
+ message += "\n"
+ message += "総合運: " + point_overall + "\n"
+ message += "恋愛運: " + point_love\
+ + add_comment_love(point_love_int) + "\n"
+ message += "金運: " + point_money\
+ + add_comment_money(point_money_int) + "\n"
+ message += "仕事運: " + point_business\
+ + add_comment_business(point_business_int) + "\n"
+ response.close()
+
+ return message
+
+ def send_mail(self):
+ """
+ Send mail with email node
+ """
+ msg = Email()
+
+ greeting = EmailBody()
+ greeting.type = 'text'
+ greeting.message = "おはよう。"
+ current_time = datetime.datetime.now()
+ greeting.message += "{}時{}分です。\n".format(
+ current_time.hour, current_time.minute)
+ greeting.message += "{} \n".format(
+ self.get_weather_forecast(lang="ja"))
+
+ content_tips = EmailBody()
+ content_tips.type = 'text'
+ tips_title, tips, detail_url = self.get_tips()
+ content_tips.message = "今日の豆知識 \n"
+ content_tips.message += "{}: {} \n".format(tips_title, tips)
+ content_tips.message += "詳細: {} \n".format(detail_url)
+
+ content_fortune = EmailBody()
+ content_fortune.type = 'text'
+ content_fortune.message = self.get_fortune()
+
+ change_line = EmailBody()
+ change_line.type = 'html'
+ change_line.message = "
"
+
+ msg.body = [greeting,
+ change_line,
+ content_tips,
+ change_line,
+ content_fortune]
+ msg.subject = "{} が起動しました".format(socket.gethostname())
+ msg.sender_address = "unitreepro@jsk.imi.i.u-tokyo.ac.jp"
+ msg.receiver_address = "unitree@jsk.imi.i.u-tokyo.ac.jp"
+
+ rospy.sleep(1)
+ rospy.loginfo("Send mail")
+ self.pub.publish(msg)
+
+
+if __name__ == '__main__':
+ RobotLaunchEmail = RobotLaunchEmail()
+ RobotLaunchEmail.set_constellation()
+ RobotLaunchEmail.send_mail()