def post(self, request, device_id): """ Send data to device serial """ try: data = request.DATA['data'] except KeyError: return Response(status=status.HTTP_400_BAD_REQUEST) try: is_encoded = request.DATA['is_base64'] needs_encoding = not strtobool(is_encoded) except KeyError: needs_encoding = True except ValueError: return Response(status=status.HTTP_400_BAD_REQUEST) if needs_encoding: data = base64.b64encode(data) username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: response = conn.send_serial_data(device_id, data) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def get(self, request, device_id=None, stream_id=None, format=None): """ Query Device Cloud for DataPoints """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) # Only show the data from the last x minutes if 'startTime' in request.GET: try: time = datetime.utcfromtimestamp( float(request.GET['startTime'])) except ValueError: return Response(status=status.HTTP_400_BAD_REQUEST) else: time = datetime.utcnow() - timedelta(minutes=5) time_no_micro = time.replace(microsecond=0) iso_time = time_no_micro.isoformat()+'z' try: data_points = conn.get_datapoints(stream_id, iso_time) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def monitor_setup(request, device_id): """ View to handle monitor setup for a device Will query for existing monitors, create a new one if none found, else kickstart existing monitor. Returns the monitor information from Device Cloud ------------------------------------------ """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) endpoint_url = reverse(monitor_receiver, request=request) # Device cloud won't allow monitors pointing to localhost, etc, # so don't even try if 'localhost' in endpoint_url or '127.0.0.1' in endpoint_url: logger.error('Rejecting attempt to create monitor to ' + endpoint_url) return Response(status=status.HTTP_400_BAD_REQUEST) try: monitors = conn.get_datapoint_monitor_for_device( device_id, endpoint_url) if monitors['resultSize'] == "0": # No existing monitors found for this device on this account, # create a new one # NOTE: The full url is generated by information passed in the # request. If the same backend is being routed to from multiple # places (reverse proxies, etc), each will generate a different url logger.info('Creating a new DataPoint monitor for device %s' % device_id) resp = conn.create_datapoint_monitor( device_id, endpoint_url, settings.SECRET_DEVICE_CLOUD_MONITOR_AUTH_USER, settings.SECRET_DEVICE_CLOUD_MONITOR_AUTH_PASS, description="XBee Wi-Fi Cloud Kit Monitor") else: # Should only have one monitor for a given device/topic if len(monitors['items']) > 1: logger.warning("Found multiple monitors for this device! " + "This should not happen!") monitor = monitors['items'][0] logger.info( 'Found an existing DataPoint monitor for %s, kicking it' % device_id) conn.kick_monitor(monitor['monId'], settings.SECRET_DEVICE_CLOUD_MONITOR_AUTH_USER, settings.SECRET_DEVICE_CLOUD_MONITOR_AUTH_PASS) # Return the original info resp = monitors except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def put(self, request, device_id=None): # First query for existing config, calculate diff username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: settings = conn.get_device_settings(device_id) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def get(self, request, device_id=None, format=None): """ Query Device Cloud to return current device settings """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: data_streams = conn.get_datastream_list(device_id=device_id) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def get(self, request, device_id=None, format=None): """ Query Device Cloud to return current device settings """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) cache = bool(strtobool(request.QUERY_PARAMS.get('cache', 'False'))) try: settings = conn.get_device_settings(device_id, cache=cache) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def get(self, request, device_id=None, format=None): """ Return a single Xbee WiFi devices, and provide links to data and config views """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: device = conn.get_device_list(device_id=device_id) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def get(self, request, format=None): """ Return a list of Xbee WiFi devices on the authenticated user's Device Cloud account """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: devices = conn.get_device_list( device_types=settings.SUPPORTED_DEVICE_TYPES) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def put(self, request, device_id, settings_group, format=None): """ Apply new settings to the device """ # Because these settings belong to a single known group, we can # construct the request for the user new_settings = {settings_group: request.DATA} username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: settings = conn.set_device_settings(device_id, new_settings) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def post(self, request, format=None): """ Provision a new device to authenticated user's Device Cloud account """ username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) if 'mac' in request.DATA: mac = request.DATA['mac'] else: return Response(status.HTTP_400_BAD_REQUEST, data="MAC address field required") try: resp = conn.provision_device(mac) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def put(self, request, device_id=None): # Basic sanity check on the values we're trying to send for group, settings in request.DATA.items(): if not type(settings) == dict: return Response(status=status.HTTP_400_BAD_REQUEST) else: for key, val in settings.items(): if not isinstance(val, (int, float, bool, str, unicode)): return Response(status=status.HTTP_400_BAD_REQUEST) username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) try: settings = conn.set_device_settings(device_id, settings=request.DATA) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)
def put(self, request, device_id): io_command_pairs = [] io_set_setting_pairs = [] io_serial_data_values = [] # Sanitize and sort inputs for name, value in request.DATA.iteritems(): # May get '/' seperators, mixed case, etc. Strip out non-alphanum # chars, make uppercase. name = str(name).translate(None, self.delchars).upper() # Check for DIO and extract the bit position of this pin match = re.match(r"(DIO)(?P<bit>[0-9]+)", name) if match: bit = match.group('bit') # Convert boolean-ish values to True/False if type(value) == str or type(value) == unicode: try: value = bool(strtobool(value)) except ValueError: # Try to catch "high"/"low" if value.lower() == "high": value = True elif value.lower() == "low": value = False else: return Response(status=status.HTTP_400_BAD_REQUEST) io_command_pairs.append((int(bit), value)) # Else see if it looks like a traditional AT command elif len(name) == 2: # M0, etc AT command, used for PWM setting # Some commands require hex strings, others integers, others # arbitrary text...ug try: # Hex if name in ['M0', 'M1', 'IC', 'PR', 'PD', 'DS']: val_str = hex(int(value)) elif (name in ['LT', 'RP', 'IR', 'IF'] or name.startswith('T') or name.startswith('Q')): val_str = str(int(value)) else: # Use as is val_str = str(value) except ValueError: return Response(status=status.HTTP_400_BAD_REQUEST) io_set_setting_pairs.append((name, val_str)) # Handle serial output. Currently don't support sending to # different targets, so combine all # serial messages into a single payload elif name.startswith("SERIAL"): io_serial_data_values.append(value) else: # Unknown command provided return Response(status=status.HTTP_400_BAD_REQUEST) username, password, cloud_fqdn = get_credentials(request) if not username or not password or not cloud_fqdn: return Response(status=status.HTTP_400_BAD_REQUEST) conn = DeviceCloudConnector(username, password, cloud_fqdn) resp = {} try: # For IO command, need to generate two bitmasks - enable and level if len(io_command_pairs): enable_mask = 0 output_mask = 0 for bit, value in io_command_pairs: enable_mask |= 1 << int(bit) output_mask |= value << int(bit) resp = conn.set_output(device_id, hex(enable_mask), hex(output_mask)) if len(io_set_setting_pairs): # Because these settings belong to a single known group, we can # construct the request for the user new_settings = {'InputOutput': {}} for name, val in io_set_setting_pairs: new_settings['InputOutput'][name] = val resp = conn.set_device_settings(device_id, new_settings) if len(io_serial_data_values): data = "".join(io_serial_data_values) data = base64.b64encode(data) resp = conn.send_serial_data(device_id, data) except HTTPError, e: return Response(status=e.response.status_code, data=e.response.text)