stress_at_work_analysis/config/models.py

536 lines
17 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from datetime import datetime
from sqlalchemy import (
TIMESTAMP,
BigInteger,
Boolean,
Column,
Float,
ForeignKey,
Integer,
SmallInteger,
String,
UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import ARRAY as PSQL_ARRAY
from sqlalchemy.dialects.postgresql import INTEGER as PSQL_INTEGER
from sqlalchemy.dialects.postgresql import JSONB as PSQL_JSONB
from sqlalchemy.dialects.postgresql import TEXT as PSQL_TEXT
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import relationship
Base = declarative_base()
class Participant(Base):
"""
A participant class, describing the participants table.
Attributes
----------
id: int
The primary key for this table.
username: str(64)
The primary pseudoanonymous identifier for each participants.
For true participants, these were assigned by E4 Connect as usernames for Empatica Studies
and had the form of uploader_0123456.
password_hash: str(128)
token: str(32)
Authentication is implemented using HTTP Basic Auth and tokens are provided for this purpose.
token_expiration_utc: datetime
Tokens expire after a preset time period.
collection_start_utc: datetime
A datetime of the first data point uploaded.
last_upload_utc: datetime
A datetime of the last data point uploaded.
day_count_uploaded: str
Days between last_upload_utc and collection_start_utc.
last_known_device_id: str(36)
Device (installation) ID that was last seen in the data.
active: bool
Is participant marked as active (i.e. collecting data)?
marked_active_utc: datetime
The time participant was first marked as active.
day_count_active: int
Days from marked_active_utc
tester: bool
Is this a tester (or a true participant)?
"""
__tablename__ = "participants"
id = Column(Integer, primary_key=True)
username = Column(String(64), index=True, unique=True)
password_hash = Column(String(128))
token = Column(String(32), index=True, unique=True)
token_expiration_utc = Column(TIMESTAMP(timezone=False))
collection_start_utc = Column(TIMESTAMP(timezone=False))
last_upload_utc = Column(TIMESTAMP(timezone=False))
day_count_uploaded = Column(SmallInteger)
last_known_device_id = Column(String(length=36), nullable=False, default="")
active = Column(Boolean, index=True, nullable=False, default=False)
marked_active_utc = Column(TIMESTAMP(timezone=False))
day_count_active = Column(SmallInteger)
tester = Column(Boolean, index=True, nullable=False, default=False)
def __repr__(self):
return "Participant()"
def __str__(self):
return "<Participant {}>".format(self.username)
class AWAREsensor(object):
"""
A general AWARE sensor class. It includes fields common to all tables/subclasses.
Attributes
----------
id: int
The primary key for each table.
_id: int
The original primary key, used in device's own MySQL database.
timestamp: int
Unixtime milliseconds since 1970.
device_id: str(36)
AWARE device UUID, a unique string of length 36.
Rather than identifying the device as the name suggests, this string changes on each (re)installation.
It is therefore better considered to be an installation ID.
Declared Attributes
-------------------
__tablename__: str
Table name used in the database.
participant_id: int
The foreign key relating (with the relationship) tables to the participants table.
"""
id = Column(BigInteger, primary_key=True, nullable=False)
_id = Column(BigInteger, nullable=False)
timestamp = Column(BigInteger, nullable=False)
device_id = Column(String(length=36), nullable=False)
@declared_attr
def __tablename__(self):
return self.__name__.lower()
@declared_attr
def participant_id(self):
return Column(
Integer, ForeignKey("participants.id"), nullable=False, index=True
)
@declared_attr
def participant(self):
return relationship("Participant", lazy="select", backref=self.__tablename__)
@declared_attr
def __table_args__(self):
return (
UniqueConstraint("device_id", "_id", name=self.__tablename__ + "_twice"),
)
# I think it makes more sense to create a Constraint
# on device_id and _id rather than relate it to participant_id.
# _id is a primary key, auto incremented by AWARE.
# However, I would expect it to reset back to 1
# if the application was reinstalled,
# similarly to how device_id resets.
class Accelerometer(Base, AWAREsensor):
double_values_0 = Column(Float, nullable=False)
double_values_1 = Column(Float, nullable=False)
double_values_2 = Column(Float, nullable=False)
accuracy = Column(SmallInteger, nullable=True)
label = Column(String, nullable=True)
class GoogleAR(Base, AWAREsensor):
__tablename__ = "google_ar"
activity_name = Column(String(32), nullable=True)
activity_type = Column(SmallInteger, nullable=True)
confidence = Column(SmallInteger, nullable=True)
activities = Column(PSQL_JSONB(none_as_null=False), nullable=True)
class Application(Base, AWAREsensor):
__tablename__ = "applications"
# package_name = Column(String, nullable=False)
# application_name = Column(String)
package_hash = Column(String(64), nullable=False)
play_store_genre = Column(String, nullable=True)
is_system_app = Column(Boolean)
class Barometer(Base, AWAREsensor):
"""
Contains the barometer sensor data.
Attributes
----------
double_values_0: float
The ambient air pressure in mbar (hPa)
accuracy: int
Sensors accuracy level, either 1, 2, or 3 (see [SensorManager](https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH))
"""
double_values_0 = Column(Float, nullable=False)
accuracy = Column(SmallInteger, nullable=True)
label = Column(String, nullable=True)
class BarometerSensor(Base, AWAREsensor):
"""
Contains the barometer sensor capabilities.
Attributes
----------
double_sensor_maximum_range: float
Maximum sensor value possible
double_sensor_minimum_delay: float
Minimum sampling delay in microseconds
sensor_name: str
double_sensor_power_ma: float
Sensors power drain in mA
double_sensor_resolution: float
Sensors resolution in sensors units
sensor_type: str
sensor_vendor: str
Sensors manufacturer
sensor_version: str
"""
__tablename__ = "barometer_sensor"
# Since this table is not really important,
# I will leave all columns as nullable. (nullable=True by default.)
double_sensor_maximum_range = Column(Float)
double_sensor_minimum_delay = Column(Float)
sensor_name = Column(String)
double_sensor_power_ma = Column(Float)
double_sensor_resolution = Column(Float)
sensor_type = Column(String)
sensor_vendor = Column(String)
sensor_version = Column(String)
class Battery(Base, AWAREsensor):
battery_status = Column(SmallInteger, nullable=False)
battery_level = Column(SmallInteger, nullable=False)
battery_scale = Column(SmallInteger, nullable=False)
battery_voltage = Column(Integer, nullable=True)
battery_temperature = Column(Integer, nullable=True)
battery_adaptor = Column(SmallInteger, nullable=True)
battery_health = Column(SmallInteger, nullable=True)
battery_technology = Column(String, nullable=True)
class Bluetooth(Base, AWAREsensor):
bt_address = Column(String(length=40), nullable=False)
bt_name = Column(String, nullable=True)
bt_rssi = Column(Integer, nullable=True)
label = Column(String, nullable=True)
class Call(Base, AWAREsensor):
"""
Contains the calls sensor information.
Attributes
----------
call_type: int
One of the Androids call types (1 incoming, 2 outgoing, 3 missed).
call_duration: int
Length of the call session in seconds.
trace: str(40)
A hash value SHA-1 of the phone number (source or target) of the call
"""
call_type = Column(SmallInteger, nullable=False)
call_duration = Column(Integer, nullable=False)
trace = Column(String(length=40), nullable=True)
class ESM(Base, AWAREsensor):
esm_status = Column(SmallInteger, nullable=False)
esm_user_answer = Column(String, nullable=True)
esm_notification_timeout = Column(SmallInteger)
esm_json = Column(PSQL_JSONB(none_as_null=False), nullable=False)
double_esm_user_answer_timestamp = Column(BigInteger, nullable=False)
esm_trigger = Column(String, nullable=True)
esm_session = Column(Integer, nullable=False)
esm_notification_id = Column(Integer, nullable=False)
esm_expiration_threshold = Column(SmallInteger)
ESM_TYPE = {
"text": 1,
"radio": 2,
"checkbox": 3,
"likert": 4,
"quick_answers": 5,
"scale": 6,
"datetime": 7,
"pam": 8,
"number": 9,
"web": 10,
"date": 11,
}
class Imperfection(Base):
__tablename__ = "imperfection"
id = Column(BigInteger, primary_key=True, nullable=False)
timestamp = Column(BigInteger, nullable=False)
error = Column(String)
data_type = Column(String)
data = Column(String)
class LightSensor(Base, AWAREsensor):
"""
Contains the light sensor data.
Note: Even though this table is named light_sensor, it actually contains what AWARE calls light data
(rather than the data about the sensor's capabilities). Cf. Barometer(Sensor) and Temperature(Sensor).
Attributes
----------
double_light_lux: float
The ambient luminance in lux units
accuracy: int
Sensors accuracy level, either 1, 2, or 3 (see [SensorManager](https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH))
"""
__tablename__ = "light_sensor"
double_light_lux = Column(Float, nullable=False)
accuracy = Column(Integer, nullable=True)
label = Column(String, nullable=True)
class Location(Base, AWAREsensor):
__tablename__ = "locations"
double_latitude = Column(Float, nullable=False)
double_longitude = Column(Float, nullable=False)
double_bearing = Column(Float)
double_speed = Column(Float)
double_altitude = Column(Float)
provider = Column(String)
accuracy = Column(Integer)
label = Column(String, nullable=True)
category = Column(PSQL_ARRAY(PSQL_TEXT), nullable=True)
category_short = Column(PSQL_ARRAY(PSQL_TEXT), nullable=True)
distance = Column(PSQL_ARRAY(PSQL_INTEGER), nullable=True)
api_response_code = Column(SmallInteger, nullable=False)
api_response = Column(String, nullable=True)
class Mic(Base, AWAREsensor):
half_s_speech = Column(Boolean, nullable=False)
rnnoutp = Column(Float, nullable=False)
flatness = Column(Float, nullable=False)
absmax = Column(Float, nullable=False)
max = Column(Float, nullable=False)
min = Column(Float, nullable=False)
# mfcc = Column(PSQL_ARRAY(PSQL_REAL, dimensions=13), nullable=False)
mfcc_0 = Column(Float, nullable=False)
mfcc_1 = Column(Float, nullable=False)
mfcc_2 = Column(Float, nullable=False)
mfcc_3 = Column(Float, nullable=False)
mfcc_4 = Column(Float, nullable=False)
mfcc_5 = Column(Float, nullable=False)
mfcc_6 = Column(Float, nullable=False)
mfcc_7 = Column(Float, nullable=False)
mfcc_8 = Column(Float, nullable=False)
mfcc_9 = Column(Float, nullable=False)
mfcc_10 = Column(Float, nullable=False)
mfcc_11 = Column(Float, nullable=False)
mfcc_12 = Column(Float, nullable=False)
class Speech(Base, AWAREsensor):
speech_proportion = Column(Float, nullable=False)
class NetworkData(Base, AWAREsensor):
__tablename__ = "network_data"
network_type = Column(SmallInteger, nullable=False)
network_subtype = Column(String(10), nullable=False)
network_state = Column(SmallInteger, nullable=True)
class NetworkTraffic(Base, AWAREsensor):
__tablename__ = "network_traffic_data"
network_type = Column(SmallInteger, nullable=False)
double_received_bytes = Column(Float, nullable=True)
double_sent_bytes = Column(Float, nullable=True)
double_received_packets = Column(Float, nullable=True)
double_sent_packets = Column(Float, nullable=True)
class Notification(Base, AWAREsensor):
__tablename__ = "notifications"
# package_name = Column(String, nullable=False)
# application_name = Column(String, nullable=False)
package_hash = Column(String(64), nullable=False)
play_store_genre = Column(String, nullable=True)
sound = Column(String, nullable=False)
vibrate = Column(String, nullable=False)
sound_app = Column(String, nullable=False)
vibrate_app = Column(String, nullable=False)
led_app = Column(String, nullable=False)
category = Column(String, nullable=False)
is_ongoing = Column(SmallInteger, nullable=False)
is_clearable = Column(SmallInteger, nullable=False)
is_group = Column(SmallInteger, nullable=True)
class Processor(Base, AWAREsensor):
double_last_user = Column(Float, nullable=False)
double_last_system = Column(Float, nullable=False)
double_last_idle = Column(Float, nullable=False)
double_user_load = Column(Float, nullable=False)
double_system_load = Column(Float, nullable=False)
double_idle_load = Column(Float, nullable=False)
class Proximity(Base, AWAREsensor):
double_proximity = Column(Float, nullable=False)
accuracy = Column(SmallInteger, nullable=True)
label = Column(String, nullable=True)
class Screen(Base, AWAREsensor):
screen_status = Column(SmallInteger)
class SMS(Base, AWAREsensor):
"""
Contains the messages sensor information.
Attributes
----------
message_type: int
Message type (1 received, 2 sent)
trace: str(40)
A hash value SHA-1 of the phone number (source or target) of the call
"""
message_type = Column(SmallInteger, nullable=False)
trace = Column(String(length=40), nullable=False)
class Temperature(Base, AWAREsensor):
"""
Contains the temperature sensor data.
Attributes
----------
temperature_celsius: float
Measured temperature in °C
accuracy: int
Sensors accuracy level, either 1, 2, or 3 (see [SensorManager](https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH))
"""
temperature_celsius = Column(Float, nullable=False)
accuracy = Column(SmallInteger, nullable=True)
label = Column(String, nullable=True)
class TemperatureSensor(Base, AWAREsensor):
"""
Contains the temperature sensor capabilities.
Attributes
----------
double_sensor_maximum_range: float
Maximum sensor value possible
double_sensor_minimum_delay: float
Minimum sampling delay in microseconds
sensor_name: str
double_sensor_power_ma: float
Sensors power drain in mA
double_sensor_resolution: float
Sensors resolution in sensors units
sensor_type: str
sensor_vendor: str
Sensors manufacturer
sensor_version: str
"""
# I left all of these nullable,
# as we haven't seen any data from this sensor anyway.
__tablename__ = "temperature_sensor"
double_sensor_maximum_range = Column(Float)
double_sensor_minimum_delay = Column(Float)
sensor_name = Column(String)
double_sensor_power_ma = Column(Float)
double_sensor_resolution = Column(Float)
sensor_type = Column(String)
sensor_vendor = Column(String)
sensor_version = Column(String)
class Timezone(Base, AWAREsensor):
timezone = Column(String, nullable=False)
class WiFi(Base, AWAREsensor):
bssid = Column(String(length=40), nullable=False)
ssid = Column(String, nullable=True)
rssi = Column(Integer, nullable=False)
security = Column(String, nullable=True)
frequency = Column(Integer, nullable=True)
label = Column(String, nullable=True)
all_AWARE_tables = [
ESM,
Location,
Screen,
LightSensor,
Call,
SMS,
Application,
Notification,
Battery,
WiFi,
Proximity,
Timezone,
Processor,
NetworkData,
NetworkTraffic,
Barometer,
BarometerSensor,
Temperature,
TemperatureSensor,
Bluetooth,
Accelerometer,
GoogleAR,
Speech,
]
all_AWARE_table_names = [table.__tablename__ for table in all_AWARE_tables]
def increment_one(ii):
return ii + 1
class AppCategories(Base):
__tablename__ = "app_categories"
id = Column(Integer, primary_key=True)
application_name = Column(String, nullable=True)
package_name = Column(String, nullable=False)
package_hash = Column(String(64), index=True, nullable=False, unique=True)
play_store_genre = Column(String, nullable=True)
play_store_response = Column(SmallInteger, nullable=False)
number_of_attempts = Column(
SmallInteger, nullable=False, default=0, onupdate=increment_one
)
last_attempt = Column(
TIMESTAMP(timezone=False),
nullable=False,
default=datetime.utcnow,
onupdate=datetime.utcnow,
)