Skip to content

Commit 7438fbb

Browse files
committed
updating the files
1 parent f90a789 commit 7438fbb

4 files changed

Lines changed: 389 additions & 21 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
/data
2-
/venv
2+
/venv
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
import logging
2+
import sys
3+
from datetime import datetime
4+
import pandas as pandas
5+
import pytz
6+
7+
# configure logging
8+
logger = logging.getLogger(__name__)
9+
logger.setLevel(logging.DEBUG)
10+
handler = logging.StreamHandler(sys.stdout)
11+
handler.setLevel(logging.DEBUG)
12+
formatter = logging.Formatter(
13+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
14+
handler.setFormatter(formatter)
15+
logger.addHandler(handler)
16+
17+
# template definitions
18+
TEMPLATE_TIME_MS = '<TIME_MS>'
19+
TEMPLATE_TIME_STR = '<TIME_STR>'
20+
21+
22+
# MAIN MAPPER FUNCTION
23+
24+
def annotate_event(event, template_timestamps=False):
25+
try:
26+
# check if event is valid
27+
valid = 'sourceId' in event and \
28+
'metricId' in event and \
29+
'value' in event and \
30+
('timestamp' in event or template_timestamps)
31+
32+
# if the event is not valid, return None
33+
if not valid:
34+
return None
35+
36+
# otherwise, return mapped event
37+
rdf_event = map_observation_to_rdf(
38+
event, template_timestamps=template_timestamps)
39+
return remove_whitespace(rdf_event) if rdf_event is not None else rdf_event
40+
41+
except Exception as e:
42+
print(e)
43+
return None
44+
45+
46+
def map_observation_to_rdf(event, template_timestamps=False):
47+
result = map_observation(source_id=event['sourceId'],
48+
metric_id=event['metricId'],
49+
value=event['value'],
50+
timestamp=event['timestamp'] if not template_timestamps else None)
51+
return result
52+
53+
54+
# MAPPING FUNCTIONS OF HEADACHE PARTS
55+
56+
def map_observation(metric_id,
57+
source_id,
58+
value,
59+
timestamp):
60+
# extract patient ID from source ID
61+
split = source_id.split(".", 1)
62+
patient_id = split[0]
63+
source_id = split[1]
64+
65+
# replace spaces by underscores in metricId
66+
metric_id = metric_id.replace(' ', '_')
67+
68+
# add suffix to sensor (sourceId) based on metricId
69+
source_id = update_source_id(source_id, metric_id)
70+
71+
# generate timestamp
72+
uuid = generate_uuid(metric_id, patient_id)
73+
if timestamp:
74+
timestamp_utc = timestamp
75+
time_str =timestamp
76+
else:
77+
timestamp_utc = TEMPLATE_TIME_MS
78+
time_str = TEMPLATE_TIME_STR
79+
80+
# map value
81+
value_str, metric_group = map_value(value, metric_id)
82+
83+
# create RDF data
84+
if metric_group == "CONTEXT":
85+
return OBSERVATION_TEMPLATE_CONTEXT_DAHCC % (uuid,
86+
uuid, source_id,
87+
uuid, uuid, metric_id,
88+
uuid, str(timestamp_utc),
89+
uuid, value
90+
)
91+
# return OBSERVATION_TEMPLATE_CONTEXT % (source_id,
92+
# patient_id, metric_id, uuid,
93+
# patient_id, metric_id, uuid,
94+
# metric_id, time_str, str(timestamp_utc), value_str)
95+
elif metric_group == "WEARABLE":
96+
return OBSERVATION_TEMPLATE_CONTEXT_DAHCC % (uuid,
97+
uuid, source_id,
98+
uuid, uuid, metric_id,
99+
uuid, str(timestamp_utc),
100+
uuid, value
101+
)
102+
103+
104+
# return OBSERVATION_TEMPLATE_WEARABLE % (source_id,
105+
# patient_id, metric_id, uuid,
106+
# patient_id, metric_id, uuid,
107+
# metric_id, time_str, str(timestamp_utc), value_str)
108+
109+
110+
def map_value(value, metric_id):
111+
value_type, metric_group = float, None
112+
if metric_id in METRIC_TYPES_CONTEXT:
113+
value_type, metric_group = METRIC_TYPES_CONTEXT[metric_id], "CONTEXT"
114+
elif metric_id in METRIC_TYPES_WEARABLE:
115+
value_type, metric_group = METRIC_TYPES_WEARABLE[metric_id], "WEARABLE"
116+
117+
if value_type == bool:
118+
processed_value = int(1) if value == 1 or value == '1' else int(0)
119+
else:
120+
processed_value = value
121+
122+
return VALUE_TEMPLATE % (processed_value, TYPE_MAP[value_type]), metric_group
123+
124+
125+
def update_source_id(source_id, metric_id):
126+
if metric_id in SENSOR_SUFFIX_MAP:
127+
return '%s.%s' % (source_id, SENSOR_SUFFIX_MAP[metric_id])
128+
else:
129+
return source_id
130+
131+
132+
# MAPPING TEMPLATES
133+
134+
EXAMPLE_OBSERVATION = """
135+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs0> <http://rdfs.org/ns/void#inDataset> <https://dahcc.idlab.ugent.be/Protego/_participant1> .
136+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs0> <https://saref.etsi.org/core/measurementMadeBy> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/70:ee:50:67:30:b2> .
137+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs0> <https://saref.etsi.org/core/relatesToProperty> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/org.dyamand.types.common.AtmosphericPressure> .
138+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs0> <https://saref.etsi.org/core/hasTimestamp> "2022-01-03T09:04:55.000000"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
139+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs0> <https://saref.etsi.org/core/hasValue> "1013.1"^^<http://www.w3.org/2001/XMLSchema#float>
140+
141+
"""
142+
143+
OBSERVATION_TEMPLATE_CONTEXT_DAHCC = """
144+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <http://rdfs.org/ns/void#inDataset> <https://dahcc.idlab.ugent.be/Protego/_participant1> .
145+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <https://saref.etsi.org/core/measurementMadeBy> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/%s> .
146+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <http://purl.org/dc/terms/isVersionOf> <https://saref.etsi.org/core/Measurement> .
147+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <https://saref.etsi.org/core/relatesToProperty> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/%s> .
148+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <https://saref.etsi.org/core/hasTimestamp> "%s"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
149+
<https://dahcc.idlab.ugent.be/Protego/_participant1/obs%s> <https://saref.etsi.org/core/hasValue> "%s"^^<http://www.w3.org/2001/XMLSchema#float> .
150+
151+
"""
152+
153+
OBSERVATION_TEMPLATE_CONTEXT = """
154+
<https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/%s>
155+
<https://saref.etsi.org/core/makesMeasurement> <http://protego.idlab.ugent.be/%s/%s/obs%s> .
156+
<http://protego.idlab.ugent.be/%s/%s/obs%s>
157+
<https://saref.etsi.org/core/relatesToProperty> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndActuators/%s> ;
158+
<https://saref.etsi.org/core/hasTimestamp> "%s"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
159+
<https://dahcc.idlab.ugent.be/Ontology/Sensors/hasTimestampUTC> "%s"^^<http://www.w3.org/2001/XMLSchema#integer> ;
160+
<https://saref.etsi.org/core/hasValue> %s .
161+
"""
162+
163+
OBSERVATION_TEMPLATE_WEARABLE = """
164+
<https://dahcc.idlab.ugent.be/Homelab/SensorsAndWearables/%s>
165+
<https://saref.etsi.org/core/makesMeasurement> <http://protego.idlab.ugent.be/%s/%s/obs%s> .
166+
<http://protego.idlab.ugent.be/%s/%s/obs%s>
167+
<https://saref.etsi.org/core/relatesToProperty> <https://dahcc.idlab.ugent.be/Homelab/SensorsAndWearables/%s> ;
168+
<https://saref.etsi.org/core/hasTimestamp> "%s"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
169+
<https://dahcc.idlab.ugent.be/Ontology/Sensors/hasTimestampUTC> "%s"^^<http://www.w3.org/2001/XMLSchema#integer> ;
170+
<https://saref.etsi.org/core/hasValue> %s .
171+
"""
172+
173+
VALUE_TEMPLATE = "\"%s\"^^%s"
174+
175+
# CONVERTERS OF JSON VALUES TO ONTOLOGY CONCEPTS
176+
177+
METRIC_TYPES_CONTEXT = {
178+
"airquality.co2": float,
179+
"airquality.voc_total": bool,
180+
"energy.consumption": float,
181+
"energy.power": float,
182+
"environment.blind": float,
183+
"environment.button": bool,
184+
"environment.dimmer": float,
185+
"environment.light": float,
186+
"environment.lightswitch": bool,
187+
"environment.motion": bool,
188+
"environment.open": bool,
189+
"environment.relativehumidity": float,
190+
"environment.relay": bool,
191+
"environment.temperature": float,
192+
"environment.voltage": float,
193+
"environment.waterRunning::bool": bool,
194+
"mqtt.lastMessage": str,
195+
"org.dyamand.aqura.AquraLocationState_Protego User": str,
196+
"org.dyamand.aqura.AquraLocationState_Protego_User": str,
197+
"org.dyamand.types.airquality.CO2": float,
198+
"org.dyamand.types.common.AtmosphericPressure": float,
199+
"org.dyamand.types.common.Loudness": float,
200+
"org.dyamand.types.common.RelativeHumidity": float,
201+
"org.dyamand.types.common.Temperature": float,
202+
"people.presence.detected": bool,
203+
"people.presence.numberDetected": float,
204+
"weather.pressure": float,
205+
"weather.rainrate": float,
206+
"weather.windspeed": float
207+
}
208+
209+
METRIC_TYPES_WEARABLE = {
210+
"org.dyamand.types.health.BodyTemperature": float,
211+
"org.dyamand.types.common.Load": float,
212+
"org.dyamand.types.health.DiastolicBloodPressure": float,
213+
"org.dyamand.types.health.HeartRate": float,
214+
"org.dyamand.types.health.SystolicBloodPressure": float,
215+
"org.dyamand.types.health.GlucoseLevel": float,
216+
"smartphone.acceleration.x": float,
217+
"smartphone.acceleration.y": float,
218+
"smartphone.acceleration.z": float,
219+
"smartphone.ambient_light": float,
220+
"smartphone.ambient_noise.amplitude": float,
221+
"smartphone.ambient_noise.frequency": float,
222+
"smartphone.application": str,
223+
"smartphone.gravity.x": float,
224+
"smartphone.gravity.y": float,
225+
"smartphone.gravity.z": float,
226+
"smartphone.gyroscope.x": float,
227+
"smartphone.gyroscope.y": float,
228+
"smartphone.gyroscope.z": float,
229+
"smartphone.keyboard": str,
230+
"smartphone.linear_acceleration.x": float,
231+
"smartphone.linear_acceleration.y": float,
232+
"smartphone.linear_acceleration.z": float,
233+
"smartphone.location.accuracy": float,
234+
"smartphone.location.altitude": float,
235+
"smartphone.location.bearing": float,
236+
"smartphone.location.latitude": float,
237+
"smartphone.location.longitude": float,
238+
"smartphone.magnetometer.x": float,
239+
"smartphone.magnetometer.y": float,
240+
"smartphone.magnetometer.z": float,
241+
"smartphone.proximity": float,
242+
"smartphone.rotation.x": float,
243+
"smartphone.rotation.y": float,
244+
"smartphone.rotation.z": float,
245+
"smartphone.screen": str,
246+
"smartphone.sleepAPI.API_confidence": float,
247+
"smartphone.sleepAPI.model_type": str,
248+
"smartphone.sleepAPI.t_start": float,
249+
"smartphone.sleepAPI.t_stop": float,
250+
"smartphone.step": float,
251+
"wearable.acceleration.x": float,
252+
"wearable.acceleration.y": float,
253+
"wearable.acceleration.z": float,
254+
"wearable.battery_level": float,
255+
"wearable.bvp": float,
256+
"wearable.gsr": float,
257+
"wearable.ibi": float,
258+
"wearable.on_wrist": bool,
259+
"wearable.skt": float
260+
}
261+
262+
SENSOR_SUFFIX_MAP = {
263+
"org.dyamand.aqura.AquraLocationState_Protego_User": "Tag",
264+
"wearable.acceleration.x": 'Accelerometer',
265+
"wearable.acceleration.y": 'Accelerometer',
266+
"wearable.acceleration.z": 'Accelerometer',
267+
"wearable.battery_level": 'BatteryLevelMeter',
268+
"wearable.bvp": 'PPGSensor',
269+
"wearable.gsr": 'GSRSensor',
270+
"wearable.ibi": 'PPGSensor',
271+
"wearable.on_wrist": 'OnWristDetector',
272+
"wearable.skt": 'Thermopile'
273+
}
274+
275+
TYPE_MAP = {
276+
float: "<http://www.w3.org/2001/XMLSchema#float>",
277+
int: "<http://www.w3.org/2001/XMLSchema#integer>",
278+
bool: "<http://www.w3.org/2001/XMLSchema#integer>",
279+
str: "<http://www.w3.org/2001/XMLSchema#string>"
280+
}
281+
282+
283+
# HELPER FUNCTIONS
284+
285+
def convert_timestamp_to_string(timestamp):
286+
return datetime.fromtimestamp(float(timestamp) / 1000.0,
287+
pytz.timezone('Europe/Brussels')). \
288+
strftime('%Y-%m-%dT%H:%M:%S')
289+
290+
291+
uuid_map = {}
292+
293+
294+
def generate_uuid(metric_id, patient_id):
295+
key = '%s' % (patient_id)
296+
if key not in uuid_map:
297+
uuid_map[key] = 0
298+
result = uuid_map[key]
299+
uuid_map[key] += 1
300+
return result
301+
302+
303+
def remove_whitespace(given_str):
304+
return ' '.join(given_str.split())
305+
306+
307+
def map_feather(file, sensors_to_map):
308+
file = pandas.read_feather(file)
309+
for sensor in sensors_to_map:
310+
df = file[file['Metric'] == sensor]
311+
for index in df.index:
312+
source = (df['Sensor'][index])
313+
metric = (df['Metric'][index])
314+
value = (df['Value'][index])
315+
timestamp = (df['Timestamp'][index])
316+
timestamp_str = str(timestamp)
317+
hour = timestamp_str[0:2]
318+
minute = timestamp_str[3:5]
319+
second = timestamp_str[6:8]
320+
millisecond = '000Z'
321+
if (timestamp_str[9:12] == ''):
322+
continue
323+
else:
324+
millisecond = timestamp_str[9:13] + 'Z'
325+
326+
327+
current_time = datetime.now()
328+
year = current_time.strftime("%Y")
329+
month = current_time.strftime("%m")
330+
day = current_time.strftime("%d")
331+
332+
try:
333+
time_value = str(year) + '-' + str(month) + '-' + str(day) + 'T' + str(hour) + ':' + str(minute) + ':' + str(second) + '.' + str(millisecond)
334+
except Exception as e:
335+
print('Exception is' + e)
336+
337+
event = {
338+
'sourceId': source,
339+
'metricId': metric,
340+
'value': value,
341+
'timestamp': time_value
342+
}
343+
result = annotate_event(event)
344+
345+
with open('/home/kush/Code/feather-RDF-mapper/data/rdfData/participant6.nt', 'a') as file:
346+
pass
347+
file.write('\n')
348+
file.write(result)
349+
if __name__ == '__main__':
350+
file = 'data/dataset_participant6.feather'
351+
sensors = ['wearable.bvp']
352+
map_feather(file= file, sensors_to_map= sensors)

0 commit comments

Comments
 (0)