Skip to content

Commit de9e076

Browse files
committed
feat: added import of State of Mind and Symptoms
1 parent 36ed826 commit de9e076

2 files changed

Lines changed: 175 additions & 2 deletions

File tree

pkg/backends/influxdb/backend.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const (
2020
MeasurementSleepAnalysisDetailed = "sleep_analysis_detailed"
2121
MeasurementSleepAnalysisAggregated = "sleep_analysis_aggregated"
2222
MeasurementSleepPhases = "sleep_phases"
23+
MeasurementStateOfMind = "state_of_mind"
24+
MeasurementSymptom = "symptom"
2325
)
2426

2527
// Backend InfluxDB is used to store ingested metrics into InfluxDB. All metrics
@@ -82,6 +84,18 @@ func (b *Backend) Write(payload *healthautoexport.Payload, targetName string) er
8284
}
8385
}
8486

87+
if len(payload.Data.StateOfMind) > 0 {
88+
if err := b.writeStateOfMind(payload.Data.StateOfMind, targetName); err != nil {
89+
return errors.Wrapf(err, "write state of mind error")
90+
}
91+
}
92+
93+
if len(payload.Data.Symptoms) > 0 {
94+
if err := b.writeSymptoms(payload.Data.Symptoms, targetName); err != nil {
95+
return errors.Wrapf(err, "write symptoms error")
96+
}
97+
}
98+
8599
return nil
86100
}
87101

@@ -237,6 +251,138 @@ func makeSleepPhasePoint(
237251
return point
238252
}
239253

254+
func (b *Backend) writeStateOfMind(states []*healthautoexport.StateOfMind, targetName string) error {
255+
logger := log.WithFields(log.Fields{
256+
"backend": b.Name(),
257+
"target": targetName,
258+
"num_states": len(states),
259+
})
260+
261+
startTime := time.Now()
262+
logger.Info("start writing all state of mind entries")
263+
264+
tags := []lp.Tag{
265+
{Key: "target_name", Value: targetName},
266+
}
267+
tags = append(tags, b.staticTags...)
268+
269+
points := make([]*write.Point, 0, len(states))
270+
for _, state := range states {
271+
point := b.createStateOfMindPoint(state, tags)
272+
if point != nil {
273+
points = append(points, point)
274+
}
275+
}
276+
277+
if len(points) > 0 {
278+
logger := logger.WithFields(log.Fields{
279+
"count": len(points),
280+
})
281+
startTime := time.Now()
282+
logger.Debug("writing state of mind points")
283+
if err := b.client.WriteMetrics(b.ctx, points...); err != nil {
284+
return errors.Wrapf(err, "write error for state of mind")
285+
}
286+
logger.WithField("elapsed", time.Since(startTime)).Debug("write state of mind points success")
287+
}
288+
289+
logger.WithFields(log.Fields{
290+
"points": len(points),
291+
"elapsed": time.Since(startTime),
292+
}).Info("write all state of mind entries success")
293+
294+
return nil
295+
}
296+
297+
func (b *Backend) createStateOfMindPoint(state *healthautoexport.StateOfMind, tags []lp.Tag) *write.Point {
298+
if state.Start.IsZero() {
299+
return nil
300+
}
301+
point := write.NewPointWithMeasurement(MeasurementStateOfMind)
302+
addTagsToPoint(point, tags)
303+
304+
point.AddTag("kind", state.Kind)
305+
if len(state.Labels) > 0 {
306+
point.AddTag("labels", strings.Join(state.Labels, ","))
307+
}
308+
if len(state.Associations) > 0 {
309+
point.AddTag("associations", strings.Join(state.Associations, ","))
310+
}
311+
312+
point.AddField("valence", state.Valence)
313+
point.AddTag("valence_classification", state.ValenceClassification)
314+
point.AddField("duration", state.End.Sub(state.Start.Time).Seconds())
315+
316+
for k, v := range state.Metadata {
317+
point.AddField(fmt.Sprintf("metadata_%s", k), v)
318+
}
319+
320+
point.SetTime(state.Start.Time)
321+
return point
322+
}
323+
324+
func (b *Backend) writeSymptoms(symptoms []*healthautoexport.Symptom, targetName string) error {
325+
logger := log.WithFields(log.Fields{
326+
"backend": b.Name(),
327+
"target": targetName,
328+
"num_symptoms": len(symptoms),
329+
})
330+
331+
startTime := time.Now()
332+
logger.Info("start writing all symptoms")
333+
334+
tags := []lp.Tag{
335+
{Key: "target_name", Value: targetName},
336+
}
337+
tags = append(tags, b.staticTags...)
338+
339+
points := make([]*write.Point, 0, len(symptoms))
340+
for _, symptom := range symptoms {
341+
point := b.createSymptomPoint(symptom, tags)
342+
if point != nil {
343+
points = append(points, point)
344+
}
345+
}
346+
347+
if len(points) > 0 {
348+
logger := logger.WithFields(log.Fields{
349+
"count": len(points),
350+
})
351+
startTime := time.Now()
352+
logger.Debug("writing symptom points")
353+
if err := b.client.WriteMetrics(b.ctx, points...); err != nil {
354+
return errors.Wrapf(err, "write error for symptoms")
355+
}
356+
logger.WithField("elapsed", time.Since(startTime)).Debug("write symptom points success")
357+
}
358+
359+
logger.WithFields(log.Fields{
360+
"points": len(points),
361+
"elapsed": time.Since(startTime),
362+
}).Info("write all symptoms success")
363+
364+
return nil
365+
}
366+
367+
func (b *Backend) createSymptomPoint(symptom *healthautoexport.Symptom, tags []lp.Tag) *write.Point {
368+
if symptom.Start.IsZero() {
369+
return nil
370+
}
371+
point := write.NewPointWithMeasurement(MeasurementSymptom)
372+
addTagsToPoint(point, tags)
373+
374+
point.AddTag("name", symptom.Name)
375+
point.AddTag("severity", symptom.Severity)
376+
point.AddTag("source", symptom.Source)
377+
378+
point.AddField("user_entered", symptom.UserEntered)
379+
point.AddField("duration", symptom.End.Sub(symptom.Start.Time).Seconds())
380+
point.AddField("cycle_start", symptom.CycleStart)
381+
382+
point.SetTime(symptom.Start.Time)
383+
return point
384+
}
385+
240386
func (b *Backend) writeWorkouts(workouts []*healthautoexport.Workout, targetName string) error {
241387
logger := log.WithFields(log.Fields{
242388
"backend": b.Name(),

pkg/healthautoexport/types.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var (
3131

3232
// TimeFormats contains all known time formats to parse timestamp by.
3333
TimeFormats = []string{
34+
time.RFC3339,
3435
// Using 24-Hour Time
3536
"2006-01-02 15:04:05 -0700",
3637
// In case General > Date & Time > 24-Hour Time is set to false
@@ -47,8 +48,10 @@ type Payload struct {
4748
}
4849

4950
type PayloadData struct {
50-
Metrics []*Metric `json:"metrics,omitempty"`
51-
Workouts []*Workout `json:"workouts,omitempty"`
51+
Metrics []*Metric `json:"metrics,omitempty"`
52+
Workouts []*Workout `json:"workouts,omitempty"`
53+
StateOfMind []*StateOfMind `json:"stateOfMind,omitempty"`
54+
Symptoms []*Symptom `json:"symptoms,omitempty"`
5255
}
5356

5457
// Metric defines a single measurement with units, as well as time-series data points.
@@ -139,6 +142,30 @@ func (m *Metric) GetUnits() Units {
139142
return m.Units
140143
}
141144

145+
// StateOfMind defines a single state of mind entry.
146+
type StateOfMind struct {
147+
ID string `json:"id"`
148+
Start *Time `json:"start"`
149+
End *Time `json:"end"`
150+
Kind string `json:"kind"`
151+
Labels []string `json:"labels"`
152+
Associations []string `json:"associations"`
153+
Valence float64 `json:"valence"`
154+
ValenceClassification string `json:"valenceClassification"`
155+
Metadata map[string]string `json:"metadata"`
156+
}
157+
158+
// Symptom defines a single symptom entry.
159+
type Symptom struct {
160+
Start *Time `json:"start"`
161+
End *Time `json:"end"`
162+
Name string `json:"name"`
163+
Severity string `json:"severity"`
164+
UserEntered bool `json:"userEntered"`
165+
Source string `json:"source"`
166+
CycleStart bool `json:"cycleStart"`
167+
}
168+
142169
// Workout defines a single recorded Workout.
143170
type Workout struct {
144171
Name string `json:"name"`

0 commit comments

Comments
 (0)