network/http_server_stream/example_client/python/example_client.py

1 #
2 # EVALUATION AND USE OF THIS SOFTWARE IS SUBJECT TO THE TERMS AND
3 # CONDITIONS OF THE CONTROLLING LICENSE AGREEMENT FOUND AT LICENSE.md
4 # IN THIS SDK. IF YOU DO NOT AGREE TO THE LICENSE TERMS AND CONDITIONS,
5 # PLEASE RETURN ALL SOURCE FILES TO SILICON LABORATORIES.
6 # (c) Copyright 2018, Silicon Laboratories Inc. All rights reserved.
7 #
8 
9 import os, sys
10 import platform
11 import datetime
12 import optparse
13 from threading import Event
14 
15 import import_gos_sdk_utils
16 
17 
18 
19 from common.gos_http_server import gos_ws_data_api
20 from common import logger_configure
21 from common import object_from_dict
22 from common import issue_event
23 
24 
25 
26 class http_server_data_api_client(object):
27 
28  ''' ******************************************************************************************* '''
29  def __init__(self, options):
30  self.logger = logger_configure(log_level=options.log_level, name='client')
31 
32  self.ws_api = gos_ws_data_api(host=options.host,
33  logger=logger_configure(log_level=options.ws_log_level, name='ws_api'),
34  disconnect_callback=self._ws_disconnect_callback)
35  self.rest_api = None
36  self.host = options.host
37  self.stop_event = Event()
38  self.stop_event.clear()
39 
40 
41  # Register the streams for which the client is listening
42  self.ws_api.register('sysinfo', self._sysinfo_client_stream_handler)
43  self.ws_api.register('version', self._version_client_stream_handler)
44 
45  self.read_led_stream = None
46  self.write_led_stream = None
47  self.read_adc_stream = None
48  self.read_time_stream = None
49 
50  # Initialize the periodic client handlers
51  if options.read_led_period:
52  self.read_led_stream = issue_event(handler=self._read_led_device_stream_handler,
53  start_now = False,
54  name ='Read LED',
55  period=options.read_led_period)
56  if options.write_led_period:
57  self.write_led_stream = issue_event(handler=self._write_led_device_stream_handler,
58  start_now = False,
59  name ='Write LED',
60  period=options.write_led_period)
61  if options.read_adc_period:
62  self.read_adc_stream = issue_event(handler=self._read_adc_device_stream_handler,
63  start_now = False,
64  name ='Read ADC',
65  period=options.read_adc_period)
66  if options.read_time_period:
67  self.read_time_stream = issue_event(handler=self._read_time_device_stream_handler,
68  start_now = False,
69  name ='Read Time',
70  period=options.read_time_period)
71 
72 
73  ''' ******************************************************************************************* '''
74  @property
75  def running(self):
76  return not self.stop_event.is_set()
77 
78 
79  ''' ******************************************************************************************* '''
80  def run_forever(self):
81  self._ws_try_connect()
82  self.stop_event.wait()
83 
84 
85  ''' ******************************************************************************************* '''
86  def stop(self):
87  self.stop_event.set()
88  if self.read_led_stream:
89  self.read_led_stream.stop()
90  if self.write_led_stream:
91  self.write_led_stream.stop()
92  if self.read_adc_stream:
93  self.read_adc_stream.stop()
94  if self.read_time_stream:
95  self.read_time_stream.stop()
96 
97 
98  ''' *******************************************************************************************
99  Try to connect to device via websocket.
100  '''
101  def _ws_try_connect(self):
102  issue_event(self._ws_try_connect_handler, name='WS Connect')
103 
104 
105  ''' ******************************************************************************************* '''
106  def _ws_try_connect_handler(self):
107  if self.running:
108  try:
109  self.logger.info('Attempting to connect to: %s' % self.ws_api.host)
110  self.ws_api.open()
111  self.logger.info('Connected')
112 
113  except Exception as e:
114  self.logger.warn('Failed to connect to websocket, err:%s' % e)
115  issue_event(self._ws_try_connect_handler, initial_delay=7, name='WS Connect')
116  return
117 
118  try:
119  self.logger.info('Listing device streams')
120  streams = self.ws_api.list()
121  stream_list = ', '.join(streams)
122  self.logger.info('Streams device is actively listing: %s' % stream_list)
123 
124  except Exception as e:
125  self.logger.warn('Failed to list device streams, err:%s' % e)
126 
127 
128  self.logger.info('Starting client stream polling loops')
129  if self.read_led_stream:
130  self.read_led_stream.start()
131  if self.write_led_stream:
132  self.write_led_stream.start()
133  if self.read_adc_stream:
134  self.read_adc_stream.start()
135  if self.read_time_stream:
136  self.read_time_stream.start()
137 
138 
139  ''' ******************************************************************************************* '''
140  def _ws_disconnect_callback(self):
141  self.logger.warn('Websocket disconnected')
142 
143  if self.read_led_stream:
144  self.read_led_stream.pause()
145  if self.write_led_stream:
146  self.write_led_stream.pause()
147  if self.read_adc_stream:
148  self.read_adc_stream.pause()
149  if self.read_time_stream:
150  self.read_time_stream.pause()
151 
152  self._ws_try_connect()
153 
154 
155 
156 
157 
158 
159 
160 
161 
162  ''' ##########################################################################################
163 
164  The following are stream handlers the device reads/writes from/to the client
165  e.g.: device -> client
166 
167  ##########################################################################################
168  '''
169 
170 
171 
172  ''' *******************************************************************************************
173  This is called when the device writes the 'version' client stream.
174  See: websocket_periodic_write_version_stream_handler() in the example app.
175  '''
176  def _version_client_stream_handler(self, stream, data):
177  self.logger.info('[Device->Client] Writing stream: %s\n%s' % (stream, data.pretty_str))
178 
179 
180  ''' *******************************************************************************************
181  This is called when the device read the 'sysinfo' client stream.
182  See: websocket_periodic_read_sysinfo_stream_handler() in the example app.
183  '''
184  def _sysinfo_client_stream_handler(self, stream, unused):
185  self.logger.info('[Device->Client] Reading stream: %s' % stream)
186 
187  response =\
188  {
189  'timestamp': '%s' % datetime.datetime.now(),
190  'platform' : ' '.join(platform.architecture()),
191  'os' : os.name
192  }
193 
194  return response
195 
196 
197 
198 
199 
200 
201  ''' ##########################################################################################
202 
203  The following are periodically invoked by this client
204  to read/write device streams.
205  e.g.:
206  client -> device
207 
208  ##########################################################################################
209  '''
210 
211  ''' *******************************************************************************************
212  This is call periodically when the client reads the device's 'led' stream.
213  See: led_stream_handler() in the example app
214  '''
215  def _read_led_device_stream_handler(self):
216  self.logger.debug('[Client->Device] Reading stream: led')
217 
218  try:
219  response = self.ws_api.read('led')
220  self.logger.info('[Client->Device] Read stream: led\n%s' % response.pretty_str)
221  except Exception as e:
222  self.logger.warn('[Client->Device] Failed to read stream, err:%s' % e)
223 
224 
225  ''' *******************************************************************************************
226  This is call periodically when the client writes the device's 'led' stream.
227  See: led_stream_handler() in the example app
228  '''
229  def _write_led_device_stream_handler(self):
230  self.logger.debug('[Client->Device] Writing stream: led')
231 
232  try:
233  request =\
234  {
235  'timestamp': '%s' % datetime.datetime.now(),
236  'value': 'toggle'
237  }
238  self.ws_api.write('led', request, timeout=7)
239  self.logger.info('[Client->Device] Wrote stream: led')
240  except Exception as e:
241  self.logger.warn('[Client->Device] Failed to write stream, err:%s' % e)
242 
243 
244  ''' *******************************************************************************************
245  This is call periodically when the client reads the device's 'adc' stream.
246  See: adc_stream_handler() in the example app
247  '''
248  def _read_adc_device_stream_handler(self):
249  self.logger.debug('[Client->Device] Reading stream: adc')
250 
251  try:
252  response = self.ws_api.read('adc')
253  self.logger.info('[Client->Device] Read stream: adc\n%s' % response.pretty_str)
254  except Exception as e:
255  self.logger.warn('[Client->Device] Failed to read stream, err:%s' % e)
256 
257 
258  ''' *******************************************************************************************
259  This is call periodically when the client reads the device's 'time' stream.
260  See: time_stream_handler() in the example app
261  '''
262  def _read_time_device_stream_handler(self):
263  self.logger.debug('[Client->Device] Reading stream: time')
264 
265  try:
266  response = self.ws_api.read('time')
267  self.logger.info('[Client->Device] Read stream: time\n%s' % response.pretty_str)
268  except Exception as e:
269  self.logger.warn('[Client->Device] Failed to read stream, err:%s' % e)
270 
271 
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 ''' ******************************************************************************************* '''
282 if __name__ == "__main__":
283  parser = optparse.OptionParser(description='This is a test client for the network.http_server_stream example app')
284 
285  parser.add_option('--host',
286  help='The IP address or hostname of the device running the example app. NOTE: The device must be on the same network as this PC')
287  parser.add_option('--log_level',
288  choices=['debug', 'info', 'warn', 'error'],
289  default='info',
290  help='Client debugging log level')
291  parser.add_option('--ws_log_level',
292  choices=['debug', 'info', 'warn', 'error'],
293  default='info',
294  help='Websocket debugging log level')
295  parser.add_option('--read_led_period', type='float', default=5.5, help='Period of the Client->Device read LED stream handler in seconds as a float [default %default]')
296  parser.add_option('--write_led_period', type='float', default=5.5, help='Period of the Client->Device write LED stream handler in seconds as a float [default %default]')
297  parser.add_option('--read_adc_period', type='float', default=5.5, help='Period of the Client->Device read ADC stream handler in seconds as a float [default %default]')
298  parser.add_option('--read_time_period', type='float', default=5.5, help='Period of the Client->Device read time stream handler in seconds as a float [default %default]')
299 
300  options, _ = parser.parse_args()
301 
302  if not options.host:
303  parser.print_help()
304  sys.stdout.write('\n\nMust provide --host option\n')
305  sys.exit(-1)
306 
307 
308  client = http_server_data_api_client(options)
309 
310  try:
311  client.run_forever()
312 
313  except KeyboardInterrupt:
314  client.stop()
315 
316 
317