wiki:S3/S3Tracking

Simple Generic Location Tracking System

S3 provides a simple generic location tracking system.

This is implemented in modules/s3db/sit.py and modules/s3/s3track.py and can be applied to virtually all entities.

Background

Location tracking means that an instance of an entity can have:

  • a base location
  • a current location X at time Y (a so-called "presence log" preserving all locations over time)

The tracking system provides the data model and an API to handle both cases.

Base Location

The base location can be implemented for an entity by adding a field location_id to the table which references the gis_location table.

As this is a pre-defined re-usable field, simply add it to your model:

table = self.define_table(tablename,
                          ...
                          self.gis_location_id(), # <= add this to give the entity a base location
                          ...)

Presence Log

To capture the current location of an instance at several timepoints, you need to make your entity "trackable".

This can be done by defining sit_trackable as super-entity:

table = self.define_table(tablename,
                          ...
                          self.super_link("track_id", "sit_trackable"), # <= add the super-entity key
                          ...)

s3db.configure(table,
               super_entity="sit_trackable", # <= configure sit_trackable as super-entity
               ...)

There is no problem to have this together with other super-entities (the number of super-entities per table is not limited):

table = self.define_table(tablename,
                          ...
                          super_link("site_id", "org_site"),
                          super_link("track_id", "sit_trackable"),
                          ...)

s3db.configure(table,
               super_entity=("org_site", "sit_trackable"), # <= multiple allowed!
               ...)

API

S3Trackable

The API uses a wrapper class for database records - S3Trackable.

You can create an S3Trackable by using the s3tracker function with the table and the record ID:

trackable = s3tracker(db.my_table, 1)

Instead of the table, you can specify the tablename:

trackable = s3tracker(tablename="my_table", record_id=1)

You can also specify a query:

query = (db.my_table.uuid == "9207324b-5dc6-439b-9410-8920cbaf8a34")
trackable = s3tracker(query=query)

or a record (must be a Row instance):

record = db(db.my_table.uuid == "9207324b-5dc6-439b-9410-8920cbaf8a34").select(limitby=(0, 1)).first()
trackable = s3tracker(record=record)

It is possible to specify multiple records for the same S3Trackable. If multiple records are specified or found, then they will be handled as one trackable object with multiple locations, i.e. if you retrieve its location, you will get a list of locations back. If you update its location, all of its records will be updated the same way.

It is possible to specify a super-entity for an S3Trackable. In this case, the tracker will automatically find the respective records in the instance table(s) and use them instead:

trackable = s3tracker(db.pr_pentity, 1) # <= the super-entity is automatically replaced by the respective instance record (e.g. in pr_person)

Base Location

To retrieve the base location of an object, use get_base_location():

base_location = s3tracker(db.pr_person, 1).get_base_location()

This will return the full gis_location record(s) for the respective base location(s).

To set the base location of an object, use set_base_location():

s3tracker(db.pr_person, 1).set_base_location(25) # <= use the record ID of a gis_location

Other ways to specify the location:

# Using a location record
location = db(db.gis_location.id == 25).select(limitby=(0, 1)).first()
s3tracker(db.pr_person, 1).set_base_location(location)

# Using another object containing a location_id
hospital = db(db.hms_hospital.id == 3).select(limitby=(0, 1)).first()
s3tracker(db.pr_person, 1).set_base_location(hospital)

# Using another trackable:
trackable = s3tracker(db.hms_hospital, 3)
s3tracker(db.pr_person, 1).set_base_location(trackable)

Current location

When setting/retrieving the current location of an object, you can additionally specify a time point:

from datetime import datetime, timedelta
one_hour_ago = datetime.utcnow() - timedelta(hours=1)
location = s3tracker(db.pr_person, 1).get_location(timestmp=one_hour_ago)

NOTE: all times in the tracking system are considered to be in UTC!

To set a current location, you can use set_location().

s3tracker(db.pr_person, 1).set_location(25, timestmp=datetime.utcnow())

If you omit the timestmp parameter, then the current server time is used.

To specify the location, you have the same options in set_location() as in set_base_location().

Check-in/out

It might be desirable to track one object together with another. For example, if a person is in a vehicle, and the vehicle's location changes, then the location of the person should change as well.

This can be achieved by using the check_in() and check_out() methods.

>>> s3tracker(db.vt_vehicle, 1).set_location(40) # <= set a current location for the vehicle
>>> s3tracker(db.pr_person, 1).check_in(db.vt_vehicle, 1) # <= check in the person to the vehicle
>>> location = s3tracker(db.pr_person, 1).get_location() # <= get the location of the person
>>> location.id
40
>>> s3tracker(db.vt_vehicle, 1).set_location(73) # <= set a new location for the vehicle
>>> location = s3tracker(db.pr_person, 1).get_location() # <= get the location of the person
>>> location.id
73
>>> s3tracker(db.pr_person, 1).check_out(db.vt_vehicle, 1) # <= check out the person from the vehicle
>>> s3tracker(db.vt_vehicle, 1).set_location(21) # <= set a new location for the vehicle
>>> location = s3tracker(db.pr_person, 1).get_location() # <= get the location of the person
>>> location.id
73

When you set the location of a checked-in object explicitly using set_location(), then the object will automatically be checked-out from wherever it has been checked-in before.

Both check_in() as well as check_out() accept the timestmp parameter to set the time of the check-in/out explicitly. If omitted, then the current server time is used.

If you specify a super-entity instance to check-in to, then the respective instance record will automatically be used:

s3tracker(db.pr_person, 1).check_in(db.org_site, 4) # <= checks-in the person to the respective org_site instance, i.e. hospital or office...

Additional Options

When retrieving locations by get_location() or get_base_location(), you can specify additional parameters for the result:

  • _fields (list/tuple of Field instances) to select fields from gis_location (None for ALL)
  • _filter (Query instance) to filter the gis_location records
  • as_rows (boolean) return the result as Rows object (work like a DAL select())

See Also

S3 Guide

BluePrint/Tracking

DeveloperGuidelines

Last modified 10 years ago Last modified on 06/13/14 12:19:35
Note: See TracWiki for help on using the wiki.