Example #1
0
def set_geofence(asset_id, geofence, inclusivity):
    """
    Set a geofence for an asset.

    First, removes all current geofences attached to the asset.
    (This is not necessary, but this app limits assets to only one
    fence for simplicity's sake.)

    Then the geofence passed as a parameter is applied to the asset.
    If the geofence is empty, clears the existing geofence.

    A random type name is associated with each fence to show
    functionality.

    Raises RuntimeError we get an error or unexpected data from mCore.
    Raises KeyError if the asset does not exist.

    """
    geofence = [(float(x), float(y)) for x, y in list(geofence)]

    a_response = fms_client.get_asset(asset_id=asset_id)
    if 'assetVO' not in a_response:
        raise KeyError('Asset does not exist')

    if 'geofenceVOs' in a_response.assetVO:
        for fence in a_response.assetVO.geofenceVOs:
            fms_client.delete_geofence(fence.geofenceId)

    if not geofence:
        # No geofence to add. Done
        return

    geo_id = {'inclusive': 1,
              'exclusive': 2,
              }
    geofence_type = str(random.randint(0, 100))

    request = webapp2.get_request()
    org_id = request.registry['session'].get('organization_id')
    fms_client.create_geofenceType(1, geofence_type)
    g_response = fms_client.create_geofence(geofence,
                                            "asset" + str(asset_id) + "_fence",
                                            geo_id[inclusivity],
                                            geofence_type,
                                            org_id)
    log.info(g_response)

    if 'entityId' in g_response:
        resp = fms_client.apply_geofence(asset_id, g_response.entityId)
        return {'code': resp.code,
                'message': resp.message}
    else:
        raise RuntimeError(str(g_response))
Example #2
0
def get_diagnostics(org_id, asset_id):
    '''
    Returns a dictionary of the obd data for one asset.

    '''
    asset_response = fms_client.get_asset(asset_id)
    device_serial = asset_response.assetVO.deviceSerial

    response = fms_client.get_diagnostic_data(device_serial)

    if not 'diagnosticDataVOs' in response:
        return

    elif len(response.diagnosticDataVOs) == 0:
        diagnostics = {asset_id: [{
            'Absolute Throttle Position': None,
            'AirIntake Temperature': None,
            'Cruise Control Status': None,
            'Cumulative Fuel Used': None,
            'Date Created': None,
            'Device Serial': device_serial,
            'Diagnostic Data Id': None,
            'Dtc Errors': None,
            'Dtc Value': None,
            'Engine Coolant Temperature': None,
            'Engine Rpm': None,
            'Ignition State': None,
            'Instantaneous Fuel Rate': None,
            'Load Percentage': None,
            'Long Term Fuel Trim': None,
            'Mass Air Flow': None,
            'Odometer Reading': None,
            'Pto Information': None,
            'Record Type': None,
            'Short Term Fuel Trim': None,
            'Speed': None
        }]}
    else:
        # Diagnostics is a data stucture of the form:
        # {asset_id: [{key1: value1, key2: value2, ... }
        #             {key1: value1, key2: value2, ... }
        #             ...
        #            ]
        # }
        diagnostics = {
            asset_id: [
                {make_readable(record[0]): record[1] for record in OBDdata}
                for OBDdata in response.diagnosticDataVOs
            ]
        }

    return diagnostics
Example #3
0
def create_current_config(org_id, asset_id):
    '''
    Creates a consumable representation of an asset's current configuration.

    Merges the current configuration of a device with the list of
    all possible features to be configured for a device of its type.

    It then transorms this information into a structure useable by
    the templating engine.

    '''
    #Get the asset's configuration and its device type's default configuration
    asset = fms_client.get_asset(asset_id)
    serial = asset.assetVO.deviceSerial
    device = device_client.get_device(org_id, serial=serial)
    type_ = device.deviceVO.deviceTypeVO.deviceTypeId

    deviceResponse = device_client.get_device_configuration(serial)
    defaultResponse = device_client.get_device_type_configuration(type_)

    #Combine the current configuration with the default one
    combined_dict = {}
    _update_combined(
        combined_dict,
        defaultResponse.deviceTypeConfigurationVO.featureVOs)

    if deviceResponse.deviceConfigurationVO is not None:
        # a device's config only exists if it's been configured previously
        _update_combined(
            combined_dict,
            deviceResponse.deviceConfigurationVO.featureVOs)

    #Create a data structure suitable for the template. Note that this
    # is specific to these applications and not especially important
    device_config_list = []
    for feature_id, feature_name in combined_dict:
        feat = {'id': feature_id,
                'name': feature_name,
                'attrs': sorted(combined_dict[(feature_id,
                                               feature_name)].values(),
                                key=lambda attr: attr.attrName)  # sort by name
                }

        device_config_list.append(feat)

    return sorted(device_config_list, key=lambda element: element['name'])
Example #4
0
def get_last_location(asset_id):
    """
    Get the last location for an asset.

    Returns a dict of lat/long and the last time updated.
    If the asset has no last location, returns None.
    If the asset doesn't exist on the account, raises KeyError.

    """
    response = fms_client.get_asset(asset_id=asset_id)

    if response.assetVO is None:
        raise KeyError("Asset Does Not Exist!")

    asset = response.assetVO
    if asset.assetLastLocationVO is None:
        return None
    else:
        last_location = asset.assetLastLocationVO
        return {'latitude': last_location.latitude,
                'longitude': last_location.longitude,
                'updated': last_location.dtUpdated}
Example #5
0
def get_geofence(asset_id):
    """Get the currently set geofence for an asset.

    Will return one of the geofences if multiple are set.

    Returns a list of [latitude, longitude] for the set geofence, if set.
    Returns None if no geofence is set
    Raises KeyError if the asset does not exist.

    """
    response = fms_client.get_asset(asset_id=asset_id)

    if response.assetVO is None:
        raise KeyError("Asset Does Not Exist!")

    if 'geofenceVOs' not in response.assetVO:
        # no geofence is set
        return None

    # Note that without str() points_string would be a suds 'Text' object
    points_string = str(response.assetVO.geofenceVOs[0].geofenceGeometry)

    # from http://bit.ly/KOB9JI (stackoverflow comment)
    # Match all numbers in the POLYGON((long lat,long lat, ...., long lat))
    # string
    nums = map(float, re.findall(
        r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",
        points_string))
        # Assume valid format

    parsed = [(latitude, longitude) for longitude, latitude in
              zip(nums[::2], nums[1::2])]

    if not parsed:
        return None
    else:
        return parsed
Example #6
0
def send_configuration(asset_id, config_data):
    '''
    Overwrites the asset's configuration with the one given on the page.

    The page's form data is parsed and sanitized, then inserted in the
    appropriate places in the default configuration. This function sends
    every feature, but notice that this isn't necessary. If only one option
    is changed, only that feature needs to be sent back to the device.

    '''
    #Get the device type's default configuration
    asset = fms_client.get_asset(asset_id)
    serial = asset.assetVO.deviceSerial
    device = device_client.get_device(asset.assetVO.organizationId,
                                      serial=serial)
    type_ = device.deviceVO.deviceTypeVO.deviceTypeId
    default = device_client.get_device_type_configuration(type_)

    # Set up default configuration details for quick access
    features = default.deviceTypeConfigurationVO.featureVOs
    feat_names = {f.featureId: f.featureName for f in features}
    default_attrs = {feature.featureId: {attribute.attrId: attribute
                                         for attribute in feature.attributeVOs}
                     for feature in features}

    # Set up form data for insertion into default_attrs. Note that this is
    # specific to this application.
    new_configs = {}
    for (feat_attr, attr_value) in config_data:
        # This is where the strange form names come in handy
        feat_id, attr_id = [int(elem) for elem in feat_attr.split('_')]
        new_configs.setdefault(feat_id, {})
        new_configs[feat_id][attr_id] = attr_value

    #Sanitize form data and insert back into the default configurations
    changed_features = []
    for feat_id in new_configs:
        changed_features.append(feat_id)

        for attr_id in new_configs[feat_id]:
            attr_value = new_configs[feat_id][attr_id]
            if attr_value == 'on':
                attr_value = '1'
            if attr_value == '':
                attr_value = None

            default_attrs[feat_id][attr_id].attrValue = attr_value

    #Revert default_configs to a nested list structure
    configuration = []

    for feat_id in changed_features:
        featureVO = device_client.create_feature(feat_id, feat_names[feat_id])
        featureVO.attributeVOs = default_attrs[feat_id].values()
        configuration.append(featureVO)

    #Note that `configuration' is now in the correct data structure for sending
    # to MAP and the device. That is, configuration is a list of features, each
    # of which is a list of attributes. Each attribute has an attrName and an
    # attrValue field, as well as some secretarial fields like min, max, and ID
    response = device_client.update_configuration(serial, configuration)
    return {'code': response.code,
            'message': response.message,
            }