1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
import dataclasses
import datetime
from enum import StrEnum
from typing import Any, Union
from mashumaro.mixins.json import DataClassJSONMixin
class SnooLevels(StrEnum):
baseline = "BASELINE"
weaning_baseline = "WEANING_BASELINE"
level1 = "LEVEL1"
level2 = "LEVEL2"
level3 = "LEVEL3"
level4 = "LEVEL4"
stop = "ONLINE"
class SnooStates(StrEnum):
baseline = "BASELINE"
level1 = "LEVEL1"
level2 = "LEVEL2"
level3 = "LEVEL3"
level4 = "LEVEL4"
stop = "ONLINE"
pretimeout = "PRETIMEOUT"
timeout = "TIMEOUT"
suspended = "SUSPENDED"
weaning_baseline = "WEANING_BASELINE"
global_settings = "GLOBAL_SETTINGS"
unrecoverable_suspended = "UNRECOVERABLE_SUSPENDED"
unrecoverable_error = "UNRECOVERABLE_ERROR"
none = "NONE"
manual = "MANUAL"
class SnooEvents(StrEnum):
TIMER = "timer"
CRY = "cry"
COMMAND = "command"
SAFETY_CLIP = "safety_clip"
LONG_ACTIVITY_PRESS = "long_activity_press"
ACTIVITY = "activity"
POWER = "power"
STATUS_REQUESTED = "status_requested"
STICKY_WHITE_NOISE_UPDATED = "sticky_white_noise_updated"
CONFIG_CHANGE = "config_change"
RESTART = "restart"
class DiaperTypes(StrEnum):
"""Diaper change types, matching what the Happiest Baby app uses"""
WET = "pee"
DIRTY = "poo"
@dataclasses.dataclass
class AuthorizationInfo:
snoo: str
aws_access: str
aws_id: str
aws_refresh: str
@dataclasses.dataclass
class AwsIOT:
awsRegion: str
clientEndpoint: str
clientReady: bool
thingName: str
@dataclasses.dataclass
class SnooDevice(DataClassJSONMixin):
serialNumber: str
firmwareVersion: str
babyIds: list[str]
name: str
deviceType: int | None = None
presence: dict | None = None
presenceIoT: dict | None = None
awsIoT: AwsIOT | None = None
lastSSID: dict | None = None
provisionedAt: str | None = None
@dataclasses.dataclass
class SnooStateMachine(DataClassJSONMixin):
up_transition: str
since_session_start_ms: int
sticky_white_noise: str
weaning: str
time_left: int
session_id: str
state: SnooStates
is_active_session: bool
down_transition: str
hold: str
audio: str
time_left_timestamp: datetime.datetime | None = None
level: SnooLevels | None = None
def __post_init__(self):
if self.time_left != -1:
self.time_left_timestamp = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
seconds=self.time_left
)
else:
self.time_left_timestamp = None
if self.up_transition == "NONE" and self.down_transition == "NONE":
self.level = SnooLevels.stop
elif self.up_transition == SnooLevels.level1:
self.level = SnooLevels.baseline
elif self.up_transition == SnooLevels.level2:
self.level = SnooLevels.level1
elif self.up_transition == SnooLevels.level3:
self.level = SnooLevels.level2
elif self.up_transition == SnooLevels.level4:
self.level = SnooLevels.level3
elif self.down_transition == SnooLevels.level3:
self.level = SnooLevels.level4
@dataclasses.dataclass
class SnooData(DataClassJSONMixin):
left_safety_clip: int
rx_signal: dict
right_safety_clip: int
sw_version: str
event_time_ms: int
state_machine: SnooStateMachine
system_state: str
event: SnooEvents
@dataclasses.dataclass
class BabySettings(DataClassJSONMixin):
carRideMode: bool
daytimeStart: int
minimalLevel: str
minimalLevelVolume: str
motionLimiter: bool
responsivenessLevel: str
soothingLevelVolume: str
weaning: bool
@dataclasses.dataclass
class BabyData(DataClassJSONMixin):
_id: str
babyName: str
breathSettingHistory: list
createdAt: str
disabledLimiter: bool
pictures: list
settings: BabySettings
sex: str
preemie: Any | None = None # Not sure what datatype this is yet & may not be supplied - boolean?
birthDate: str | None = None
expectedBirthDate: str | None = None
startedUsingSnooAt: str | None = None
updatedAt: str | None = None
@dataclasses.dataclass
class DiaperData(DataClassJSONMixin):
"""Data for diaper change activities"""
types: list[DiaperTypes]
def __post_init__(self):
if not self.types:
raise ValueError("DiaperData.types cannot be empty or None")
self.types = [DiaperTypes(dt) for dt in self.types]
@dataclasses.dataclass
class BreastfeedingData(DataClassJSONMixin):
lastUsedBreast: str
totalDuration: int
left: dict | None = None
right: dict | None = None
@dataclasses.dataclass
class DiaperActivity(DataClassJSONMixin):
id: str
type: str
startTime: str
babyId: str
userId: str
data: DiaperData
createdAt: str
updatedAt: str
note: str | None = None
@dataclasses.dataclass
class BreastfeedingActivity(DataClassJSONMixin):
id: str
type: str
startTime: str
endTime: str
babyId: str
userId: str
data: BreastfeedingData
createdAt: str
updatedAt: str
Activity = Union[DiaperActivity, BreastfeedingActivity]
|