sesame_server.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import os.path as osp
4 import time
5 
6 import requests
7 import rospy
8 from sesame_ros.srv import Command
9 from sesame_ros.srv import CommandResponse
10 from sesame_ros.srv import Status
11 from sesame_ros.srv import StatusResponse
12 
13 
14 class SesameServer(object):
15 
16  def __init__(self):
17  auth_token = rospy.get_param('~auth_token')
18  if osp.isfile(osp.expanduser(auth_token)):
19  with open(osp.expanduser(auth_token), 'r') as f:
20  self.auth_token = f.readline().rstrip()
21  else:
22  self.auth_token = auth_token
23  self.device_id = rospy.get_param('~device_id', None)
24  self.nickname = rospy.get_param('~nickname', None)
25  self.command_timeout = rospy.get_param('~command_timeout', 60)
26  self.status_server = rospy.Service(
27  '~get_status', Status, self.get_sesame_status)
28  self.sync_server = rospy.Service(
29  '~force_sync', Command, self.force_sync)
30  self.lock_server = rospy.Service('~lock', Command, self.lock)
31  self.unlock_server = rospy.Service('~unlock', Command, self.unlock)
32 
33  def _get_sesame(self):
34  ret = requests.get(
35  'https://api.candyhouse.co/public/sesames',
36  headers={'Authorization': self.auth_token})
37  if ret.status_code == 200:
38  sesames = ret.json()
39  # Search by device_id or nickname
40  if self.device_id is not None or self.nickname is not None:
41  # First, search by device_id
42  for sesame_ in sesames:
43  if self.device_id == sesame_['device_id']:
44  self.sesame = sesame_
45  break
46  # Second, search by nickname
47  if not hasattr(self, 'sesame'):
48  for sesame_ in sesames:
49  if self.nickname == sesame_['nickname'] and \
50  not hasattr(self, 'sesame'):
51  self.sesame = sesame_
52  elif (self.nickname == sesame_['nickname'] and
53  hasattr(self, 'sesame')):
54  rospy.logwarn(
55  'Multiple Sesames found for nickname [{}]. '
56  'The first found Sesame will be used.'.
57  format(self.nickname))
58  continue
59  if not hasattr(self, 'sesame'):
60  rospy.logwarn(
61  'Neither [~device_id] nor [~nickname] matched. '
62  'The first found Sesame will be used.')
63  self.sesame = sesames[0]
64  else:
65  rospy.logwarn(
66  'Neither [~device_id] nor [~nickname] is specified. '
67  'The first found Sesame will be used.')
68  self.sesame = sesames[0]
69  else:
70  rospy.logerr('[{}] {}'.format(ret.status_code, ret.text))
71  rospy.logerr('No Sesames found.')
72  self.sesame = {'nickname': None, 'serial': None, 'device_id': None}
73 
74  def _get_sesame_status(self):
75  battery = None
76  locked = None
77  responsive = None
78  if not hasattr(self, 'sesame'):
79  self._get_sesame()
80  if self.sesame['device_id'] is not None:
81  ret = requests.get(
82  'https://api.candyhouse.co/public/sesame/{}'.
83  format(str(self.sesame['device_id'])),
84  headers={'Authorization': self.auth_token})
85  if ret.status_code == 200:
86  battery = int(ret.json()['battery'])
87  locked = bool(ret.json()['locked'])
88  responsive = bool(ret.json()['responsive'])
89  else:
90  rospy.logerr('[{}] {}'.format(ret.status_code, ret.text))
91  return self.sesame['nickname'], self.sesame['serial'], \
92  self.sesame['device_id'], battery, locked, responsive
93 
94  def get_sesame_status(self, req):
95  return StatusResponse(*self._get_sesame_status())
96 
97  def _post_command(self, command):
98  if not hasattr(self, 'sesame'):
99  self._get_sesame()
100  ret = requests.post(
101  'https://api.candyhouse.co/public/sesame/{}'.
102  format(str(self.sesame['device_id'])),
103  headers={'Authorization': self.auth_token},
104  json={'command': command})
105  if ret.status_code == 200:
106  task_id = ret.json()['task_id']
107  return task_id
108  else:
109  rospy.logerr('[{}] {}'.format(ret.status_code, ret.text))
110  return None
111 
112  def _get_task_status(self, task_id):
113  status = None
114  successful = None
115  error = None
116  ret = requests.get(
117  'https://api.candyhouse.co/public/action-result?task_id={}'.
118  format(task_id),
119  headers={'Authorization': self.auth_token})
120  if ret.status_code == 200:
121  status = ret.json()['status']
122  if status == 'terminated':
123  successful = bool(ret.json()['successful'])
124  error = str(ret.json().get('error'))
125  else:
126  rospy.logerr('[{}] {}'.format(ret.status_code, ret.text))
127  return status, successful, error
128 
129  def _post_command_and_wait(self, command, timeout):
130  time_limit = time.time() + timeout
131  task_id = self._post_command(command)
132  time.sleep(3.0)
133  status, successful, error = self._get_task_status(task_id)
134  while status != 'terminated':
135  if time.time() > time_limit:
136  rospy.logerr('Operation Timeout. command: {}'.format(command))
137  # Wait for updating status
138  time.sleep(5.0)
139  status, successful, error = self._get_task_status(task_id)
140  break
141  elif status is None:
142  rospy.logerr('Task status is None.')
143  break
144  else: # status == 'processing'
145  time.sleep(1.0)
146  status, successful, error = self._get_task_status(task_id)
147  return status, successful, error
148 
149  def force_sync(self, req):
150  return CommandResponse(
151  *self._post_command_and_wait('sync', self.command_timeout))
152 
153  def lock(self, req):
154  return CommandResponse(
155  *self._post_command_and_wait('lock', self.command_timeout))
156 
157  def unlock(self, req):
158  return CommandResponse(
159  *self._post_command_and_wait('unlock', self.command_timeout))
160 
161 
162 if __name__ == '__main__':
163  rospy.init_node('sesame_server')
164  app = SesameServer()
165  rospy.spin()
def _get_task_status(self, task_id)
def get_sesame_status(self, req)
def _post_command(self, command)
def _post_command_and_wait(self, command, timeout)


sesame_ros
Author(s): Yuto Uchimi
autogenerated on Tue May 11 2021 02:55:52