| Index: components/cloud_devices/tools/prototype/prototype.py
|
| diff --git a/components/cloud_devices/tools/prototype/prototype.py b/components/cloud_devices/tools/prototype/prototype.py
|
| index f6fc97a38eab362efcc1466b54750f2733d1fcac..7d819aba0c852ca95880a0b57f2e20d37c2a3fa8 100755
|
| --- a/components/cloud_devices/tools/prototype/prototype.py
|
| +++ b/components/cloud_devices/tools/prototype/prototype.py
|
| @@ -20,6 +20,7 @@ import base64
|
| import datetime
|
| import json
|
| import os
|
| +import random
|
| import subprocess
|
| import time
|
| import traceback
|
| @@ -35,13 +36,13 @@ from tornado.ioloop import IOLoop
|
|
|
| _OAUTH_SCOPE = 'https://www.googleapis.com/auth/clouddevices'
|
|
|
| -_API_CLIENT_FILE = 'config.json'
|
| +_CONFIG_FILE = 'config.json'
|
| _API_DISCOVERY_FILE = 'discovery.json'
|
| _DEVICE_STATE_FILE = 'device_state.json'
|
|
|
| -_DEVICE_SETUP_SSID = 'GCDPrototype.camera.privet'
|
| +_DEVICE_SETUP_SSID = 'GCD Prototype %02d..Bcamprv'
|
| _DEVICE_NAME = 'GCD Prototype'
|
| -_DEVICE_TYPE = 'camera'
|
| +_DEVICE_TYPE = 'vendor'
|
| _DEVICE_PORT = 8080
|
|
|
| DEVICE_DRAFT = {
|
| @@ -64,12 +65,12 @@ DEVICE_DRAFT = {
|
| }
|
| }
|
|
|
| -wpa_supplicant_cmd = 'wpa_supplicant -Dwext -iwlan0 -cwpa_supplicant.conf'
|
| -ifconfig_cmd = 'ifconfig wlan0 192.168.0.3'
|
| +wpa_supplicant_cmd = 'wpa_supplicant -Dwext -i%s -cwpa_supplicant.conf'
|
| +ifconfig_cmd = 'ifconfig %s 192.168.0.3'
|
| hostapd_cmd = 'hostapd hostapd-min.conf'
|
| -dhclient_release = 'dhclient -r wlan0'
|
| -dhclient_renew = 'dhclient wlan0'
|
| -dhcpd_cmd = 'udhcpd -f /etc/udhcpd.conf'
|
| +dhclient_release = 'dhclient -r %s'
|
| +dhclient_renew = 'dhclient %s'
|
| +dhcpd_cmd = 'udhcpd -f udhcpd.conf'
|
|
|
| wpa_supplicant_conf = 'wpa_supplicant.conf'
|
|
|
| @@ -84,8 +85,22 @@ network={
|
| psk="%s"
|
| }"""
|
|
|
| -led_path = '/sys/class/leds/ath9k_htc-phy0/'
|
| +hostapd_conf = 'hostapd-min.conf'
|
|
|
| +hostapd_template = """
|
| +interface=%s
|
| +driver=nl80211
|
| +ssid=%s
|
| +channel=1
|
| +"""
|
| +
|
| +udhcpd_conf = 'udhcpd.conf'
|
| +
|
| +udhcpd_template = """
|
| +start 192.168.0.20
|
| +end 192.168.0.254
|
| +interface %s
|
| +"""
|
|
|
| class DeviceUnregisteredError(Exception):
|
| pass
|
| @@ -105,7 +120,7 @@ class CommandWrapperReal(object):
|
| """Command wrapper that executs shell commands."""
|
|
|
| def __init__(self, cmd):
|
| - if type(cmd) == str:
|
| + if type(cmd) in [str, unicode]:
|
| cmd = cmd.split()
|
| self.cmd = cmd
|
| self.cmd_str = ' '.join(cmd)
|
| @@ -160,8 +175,9 @@ class CloudCommandHandlerFake(object):
|
| class CloudCommandHandlerReal(object):
|
| """Executes device commands."""
|
|
|
| - def __init__(self, ioloop):
|
| + def __init__(self, ioloop, led_path):
|
| self.ioloop = ioloop
|
| + self.led_path = led_path
|
|
|
| def handle_command(self, command_name, args):
|
| if command_name == 'flashLED':
|
| @@ -180,7 +196,7 @@ class CloudCommandHandlerReal(object):
|
| if not times:
|
| return
|
|
|
| - file_trigger = open(os.path.join(led_path, 'brightness'), 'w')
|
| + file_trigger = open(os.path.join(self.led_path, 'brightness'), 'w')
|
|
|
| if value:
|
| file_trigger.write('1')
|
| @@ -202,10 +218,12 @@ class WifiHandler(object):
|
| """Token is optional, and all delegates should support it being None."""
|
| raise Exception('Unhandled condition: WiFi connected')
|
|
|
| - def __init__(self, ioloop, state, delegate):
|
| + def __init__(self, ioloop, state, config, setup_ssid, delegate):
|
| self.ioloop = ioloop
|
| self.state = state
|
| self.delegate = delegate
|
| + self.setup_ssid = setup_ssid
|
| + self.interface = config['wireless_interface']
|
|
|
| def start(self):
|
| raise Exception('Start not implemented!')
|
| @@ -221,13 +239,18 @@ class WifiHandlerReal(WifiHandler):
|
| devices for testing the wifi-specific logic.
|
| """
|
|
|
| - def __init__(self, ioloop, state, delegate):
|
| - super(WifiHandlerReal, self).__init__(ioloop, state, delegate)
|
| + def __init__(self, ioloop, state, config, setup_ssid, delegate):
|
| + super(WifiHandlerReal, self).__init__(ioloop, state, config,
|
| + setup_ssid, delegate)
|
|
|
| - self.command_wrapper = CommandWrapperReal
|
| - self.hostapd = self.CommandWrapper(hostapd_cmd)
|
| - self.wpa_supplicant = self.CommandWrapper(wpa_supplicant_cmd)
|
| - self.dhcpd = self.CommandWrapper(dhcpd_cmd)
|
| + if config['simulate_commands']:
|
| + self.command_wrapper = CommandWrapperFake
|
| + else:
|
| + self.command_wrapper = CommandWrapperReal
|
| + self.hostapd = self.command_wrapper(hostapd_cmd)
|
| + self.wpa_supplicant = self.command_wrapper(
|
| + wpa_supplicant_cmd % self.interface)
|
| + self.dhcpd = self.command_wrapper(dhcpd_cmd)
|
|
|
| def start(self):
|
| if self.state.has_wifi():
|
| @@ -236,21 +259,30 @@ class WifiHandlerReal(WifiHandler):
|
| self.start_hostapd()
|
|
|
| def start_hostapd(self):
|
| + hostapd_config = open(hostapd_conf, 'w')
|
| + hostapd_config.write(hostapd_template % (self.interface, self.setup_ssid))
|
| + hostapd_config.close()
|
| +
|
| self.hostapd.start()
|
| time.sleep(3)
|
| - self.run_command(ifconfig_cmd)
|
| + self.run_command(ifconfig_cmd % self.interface)
|
| self.dhcpd.start()
|
|
|
| def switch_to_wifi(self, ssid, passwd, token):
|
| try:
|
| + udhcpd_config = open(udhcpd_conf, 'w')
|
| + udhcpd_config.write(udhcpd_template % self.interface)
|
| + udhcpd_config.close()
|
| +
|
| wpa_config = open(wpa_supplicant_conf, 'w')
|
| wpa_config.write(wpa_supplicant_template % (ssid, passwd))
|
| wpa_config.close()
|
| +
|
| self.hostapd.end()
|
| self.dhcpd.end()
|
| self.wpa_supplicant.start()
|
| - self.run_command(dhclient_release)
|
| - self.run_command(dhclient_renew)
|
| + self.run_command(dhclient_release % self.interface)
|
| + self.run_command(dhclient_renew % self.interface)
|
|
|
| self.state.set_wifi(ssid, passwd)
|
| self.delegate.on_wifi_connected(token)
|
| @@ -276,8 +308,9 @@ class WifiHandlerReal(WifiHandler):
|
| class WifiHandlerPassthrough(WifiHandler):
|
| """Passthrough wifi handler."""
|
|
|
| - def __init__(self, ioloop, state, delegate):
|
| - super(WifiHandlerPassthrough, self).__init__(ioloop, state, delegate)
|
| + def __init__(self, ioloop, state, config, setup_ssid, delegate):
|
| + super(WifiHandlerPassthrough, self).__init__(ioloop, state, config,
|
| + setup_ssid, delegate)
|
|
|
| def start(self):
|
| self.delegate.on_wifi_connected(None)
|
| @@ -373,6 +406,33 @@ class State(object):
|
| return self.device_id_
|
|
|
|
|
| +class Config(object):
|
| + """Configuration parameters (should not change)"""
|
| + def __init__(self):
|
| + if not os.path.isfile(_CONFIG_FILE):
|
| + config = {
|
| + 'oauth_client_id': '',
|
| + 'oauth_secret': '',
|
| + 'api_key': '',
|
| + 'wireless_interface': ''
|
| + }
|
| + config_f = open(_CONFIG_FILE + '.sample', 'w')
|
| + config_f.write(json.dumps(credentials, sort_keys=True,
|
| + indent=2, separators=(',', ': ')))
|
| + config_f.close()
|
| + raise Exception('Missing ' + _CONFIG_FILE)
|
| +
|
| + config_f = open(_CONFIG_FILE)
|
| + config = json.load(config_f)
|
| + config_f.close()
|
| +
|
| + self.config = config
|
| +
|
| + def __getitem__(self, item):
|
| + if item in self.config:
|
| + return self.config[item]
|
| + return None
|
| +
|
| class MDnsWrapper(object):
|
| """Handles mDNS requests to device."""
|
|
|
| @@ -432,28 +492,13 @@ class CloudDevice(object):
|
| def on_device_stopped(self):
|
| raise Exception('Not implemented: Device stopped')
|
|
|
| - def __init__(self, ioloop, state, command_wrapper, delegate):
|
| + def __init__(self, ioloop, state, config, command_wrapper, delegate):
|
| self.state = state
|
| self.http = httplib2.Http()
|
| - if not os.path.isfile(_API_CLIENT_FILE):
|
| - credentials = {
|
| - 'oauth_client_id': '',
|
| - 'oauth_secret': '',
|
| - 'api_key': ''
|
| - }
|
| - credentials_f = open(_API_CLIENT_FILE + '.samlpe', 'w')
|
| - credentials_f.write(json.dumps(credentials, sort_keys=True,
|
| - indent=2, separators=(',', ': ')))
|
| - credentials_f.close()
|
| - raise Exception('Missing ' + _API_CLIENT_FILE)
|
| -
|
| - credentials_f = open(_API_CLIENT_FILE)
|
| - credentials = json.load(credentials_f)
|
| - credentials_f.close()
|
|
|
| - self.oauth_client_id = credentials['oauth_client_id']
|
| - self.oauth_secret = credentials['oauth_secret']
|
| - self.api_key = credentials['api_key']
|
| + self.oauth_client_id = config['oauth_client_id']
|
| + self.oauth_secret = config['oauth_secret']
|
| + self.api_key = config['api_key']
|
|
|
| if not os.path.isfile(_API_DISCOVERY_FILE):
|
| raise Exception('Download https://developers.google.com/'
|
| @@ -470,7 +515,7 @@ class CloudDevice(object):
|
| self.device_id = None
|
| self.credentials = None
|
| self.delegate = delegate
|
| - self.command_handler = command_wrapper(ioloop)
|
| + self.command_handler = command_wrapper
|
|
|
| def try_start(self, token):
|
| """Tries start or register device."""
|
| @@ -682,24 +727,35 @@ class WebRequestHandler(WifiHandler.Delegate, CloudDevice.Delegate):
|
| return 'complete'
|
|
|
| def __init__(self, ioloop, state):
|
| - if os.path.exists('on_real_device'):
|
| + self.config = Config()
|
| +
|
| + if self.config['on_real_device']:
|
| mdns_wrappers = CommandWrapperReal
|
| - cloud_wrapper = CloudCommandHandlerReal
|
| wifi_handler = WifiHandlerReal
|
| - self.setup_real()
|
| else:
|
| mdns_wrappers = CommandWrapperReal
|
| - cloud_wrapper = CloudCommandHandlerFake
|
| wifi_handler = WifiHandlerPassthrough
|
| +
|
| +
|
| + if self.config['led_path']:
|
| + cloud_wrapper = CloudCommandHandlerReal(ioloop,
|
| + self.config['led_path'])
|
| + self.setup_real(self.config['led_path'])
|
| + else:
|
| + cloud_wrapper = CloudCommandHandlerFake(ioloop)
|
| self.setup_fake()
|
|
|
| - self.cloud_device = CloudDevice(ioloop, state, cloud_wrapper, self)
|
| - self.wifi_handler = wifi_handler(ioloop, state, self)
|
| + self.setup_ssid = _DEVICE_SETUP_SSID % random.randint(0,99)
|
| + self.cloud_device = CloudDevice(ioloop, state, self.config,
|
| + cloud_wrapper, self)
|
| + self.wifi_handler = wifi_handler(ioloop, state, self.config,
|
| + self.setup_ssid, self)
|
| self.mdns_wrapper = MDnsWrapper(mdns_wrappers)
|
| self.on_wifi = False
|
| self.registered = False
|
| self.in_session = False
|
| self.ioloop = ioloop
|
| +
|
| self.handlers = {
|
| '/internal/ping': self.do_ping,
|
| '/privet/info': self.do_info,
|
| @@ -733,14 +789,14 @@ class WebRequestHandler(WifiHandler.Delegate, CloudDevice.Delegate):
|
| print 'Skipping device setup'
|
|
|
| @staticmethod
|
| - def setup_real():
|
| + def setup_real(led_path):
|
| file_trigger = open(os.path.join(led_path, 'trigger'), 'w')
|
| file_trigger.write('none')
|
| file_trigger.close()
|
|
|
| def start(self):
|
| self.wifi_handler.start()
|
| - self.mdns_wrapper.set_setup_name(_DEVICE_SETUP_SSID)
|
| + self.mdns_wrapper.set_setup_name(self.setup_ssid)
|
| self.mdns_wrapper.start()
|
|
|
| @get_only
|
|
|