Skip to content

Repository files navigation

AWARE: ESM

Swift Package Manager compatible

Aware ESM (com.awareframework.ios.sensor.esm) is a plugin for the AWARE Framework. It loads Experience Sampling Method (ESM) survey schedules from JSON, schedules local notifications, presents survey items through the provided SwiftUI views, and stores answer, dismissal, and expiration events.

Requirements

iOS 16 or later.

Installation

You can integrate this framework into your project via Swift Package Manager (SwiftPM).

SwiftPM

  1. Open Package Manager Windows

    • Open Xcode -> Select Menu Bar -> File -> App Package Dependencies...
  2. Find the package using the manager

    • Select Search Package URL and type git@github.com:awareframework/com.awareframework.ios.sensor.esm.git
  3. Import the package into your target.

  4. Import the library into your source code.

import com_awareframework_ios_sensor_esm

Public Functions

ESMSensor

  • init(_ config: ESMSensor.Config): Initializes the ESM sensor with the optional configuration.
  • start(): Requests local notification permission and posts the ESM start notification.
  • stop(): Posts the ESM stop notification.
  • sync(force:): Syncs stored ESM response records.
  • loadSchedules(from jsonString: String): Loads schedule JSON from a string and activates local notifications.
  • loadSchedules(from data: Data): Loads schedule JSON from raw data.
  • loadSchedules(from url: URL): Loads schedule JSON from a local file URL.
  • submitAnswer(item:scheduleId:answer:notificationTime:): Saves an answered ESM item.
  • dismissESM(item:scheduleId:notificationTime:): Saves a dismissed ESM item.
  • expireESM(item:scheduleId:notificationTime:): Saves an expired ESM item.

ESMScheduleManager

  • loadSchedules(from:): Parses and activates ESM schedules.
  • activateSchedules(_:): Replaces the current schedule set and reschedules notifications.
  • activeSchedules(): Returns schedules that are currently within their start and end date window.
  • loadedSchedules(): Returns all persisted schedules.
  • clearSchedules(): Removes persisted schedules and pending ESM notifications.
  • requestPermission(completion:): Requests local notification permission.
  • schedule(from:): Resolves a notification payload to an active, non-expired schedule.

ESMSensor.Config

Class to hold the configuration of the sensor.

Fields

  • sensorObserver: ESMSensorObserver?: Callback for schedule and response events.
  • enabled: Bool: Sensor is enabled or not. (default = false)
  • debug: Bool: Enables or disables logging to the Xcode console. (default = false)
  • label: String: Label for the data. (default = "")
  • deviceId: String: Device ID associated with events and the sensor.
  • dbType: DatabaseType: Database engine used for saving data.
  • dbPath: String: Path of the database.
  • dbHost: String?: Host for syncing the database.

Supported ESM types

TypeNameJSON fields
1Free Textcommon fields
2Radioesm_radios
3Checkboxesm_checkboxes
4Likert Scaleesm_likert_max, esm_likert_min_label, esm_likert_max_label, esm_likert_step
5Quick Answeresm_quick_answers
6Scaleesm_scale_min, esm_scale_max, esm_scale_start, esm_scale_min_label, esm_scale_max_label, esm_scale_step
7DateTimecommon fields
8PAM (Photographic Affect Meter)common fields
9Numericcommon fields
10Webesm_url
11Date Pickercommon fields
13Clockcommon fields
14Pictureesm_camera
15Audiocommon fields
16Videoesm_camera

Schedule JSON

The schedule JSON is an array of schedule objects. Dates use MM-dd-yyyy format.

[
{
"schedule_id": "daily_mood",
"hours": [9, 17],
"start_date": "01-01-2026",
"end_date": "12-31-2050",
"expiration": 30,
"randomize": 10,
"notification_title": "Daily Survey",
"notification_body": "Please answer a few questions",
"interface": 0,
"esms": [
{
"esm": {
"esm_type": 4,
"esm_title": "How are you feeling?",
"esm_instructions": "Choose a number from 1 to 5",
"esm_likert_max": 5,
"esm_likert_max_label": "Great",
"esm_likert_min_label": "Poor",
"esm_likert_step": 1,
"esm_submit": "Submit",
"esm_trigger": "daily_mood_0_likert",
"esm_expiration_threshold": 60,
"esm_na": 0
}
}
]
}
]

A complete all-types sample is available at Examples/esm_all_types_sample.json.

Broadcasts

Fired Broadcasts

  • ESMSensor.ACTION_AWARE_ESM_START: fired when the ESM sensor starts.
  • ESMSensor.ACTION_AWARE_ESM_STOP: fired when the ESM sensor stops.
  • ESMSensor.ACTION_AWARE_ESM_ANSWERED: fired when an ESM response is saved.
  • ESMSensor.ACTION_AWARE_ESM_DISMISSED: fired when an ESM item is dismissed.
  • ESMSensor.ACTION_AWARE_ESM_EXPIRED: fired when an ESM item expires.
  • ESMSensor.ACTION_AWARE_ESM_SYNC: fired when ESM data sync starts.
  • ESMSensor.ACTION_AWARE_ESM_SYNC_COMPLETION: fired when ESM data sync completes.

Data Representations

ESM Data

FieldTypeDescription
idInt64Local database primary key
deviceIdStringAWARE device UUID
timestampInt64Unix time in milliseconds when the record was created
timezoneIntRaw timezone offset of the device
osStringOperating system of the device
jsonVersionIntJSON schema version
labelStringCustomizable data label
scheduleIdStringParent schedule ID
esmTriggerStringESM trigger identifier
esmTypeIntNumeric ESM type
esmTitleStringQuestion title
esmInstructionsStringQuestion instructions
esmAnswerStringAnswer value. Multi-value answers can be JSON encoded
esmAnswerTimeInt64Unix time in milliseconds when the answer was submitted
esmStatusInt0=new, 1=answered, 2=dismissed, 3=expired
esmNotificationTimeInt64Unix time in milliseconds when the notification fired

Example Usage

letsensor=ESMSensor(ESMSensor.Config().apply{ config in
config.debug =true
config.dbType =.sqlite
config.dbPath ="aware_esm"
config.dbTableName =ESMData.databaseTableName
config.sensorObserver =Observer()})
sensor.start()leturl=Bundle.main.url(forResource:"esm_schedule", withExtension:"json")!
try sensor.loadSchedules(from: url)
classObserver:ESMSensorObserver{func onScheduleLoaded(schedules:[ESMSchedule]){print("Loaded schedules:", schedules.count)}func onESMAnswered(data:ESMData){print("Answered:", data.esmTrigger, data.esmAnswer)}func onESMDismissed(data:ESMData){print("Dismissed:", data.esmTrigger)}func onESMExpired(data:ESMData){print("Expired:", data.esmTrigger)}}

Presenting an ESM form

The package includes SwiftUI views for supported ESM item types and ESMFormView for rendering a full schedule.

ESMFormView(
schedule: schedule,
notificationTime: notificationTime,
onCompleted:{ answers infor(trigger, answer)in answers {letitem= schedule.esms.first{ $0.esm.esmTrigger == trigger }?.esm
iflet item {
sensor.submitAnswer(
item: item,
scheduleId: schedule.scheduleId,
answer: answer,
notificationTime: notificationTime
)}}},
onDismissed:{forwrapperin schedule.esms {
sensor.dismissESM(
item: wrapper.esm,
scheduleId: schedule.scheduleId,
notificationTime: notificationTime
)}})

PAM (Photographic Affect Meter)

The PAM question type (type 8) presents a 4×4 grid of photographs arranged on the circumplex model of affect (valence × arousal). The user selects the image that best matches their current emotional state.

Images are sourced from the smalldatalab/android-pam repository and are fetched at runtime from:

https://raw.githubusercontent.com/smalldatalab/android-pam/master/app/src/main/assets/pam_images/{id}_{name}/{id}_1.jpg

The 16 affect categories are arranged as follows:

Unpleasant ←→ Pleasant
High ArousalAfraidTenseExcited
FrustratedAngryHappy
MiserableSadCalm
Low ArousalGloomyTiredSleepy

Reference:

Pollak, J. P., Adams, P., & Gay, G. (2011). PAM: a photographic affect meter for frequent, in situ measurement of affect. In Proceedings of the SIGCHI Conference on Human Factors in Computing Systems (CHI '11), pp. 725–734. ACM. https://dl.acm.org/doi/10.1145/1978942.1979047

Related Links

Author

Yuuki Nishiyama (The University of Tokyo), nishiyama@csis.u-tokyo.ac.jp

License

Copyright (c) 2025 AWARE Mobile Context Instrumentation Middleware/Framework (http://www.awareframework.com)

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages