My wife and I are expecting our first kid in a few months and suffice to say, we’re pretty excited to keep tabs on the whole process. Right off the bat a couple of friends suggested a variety of pregnancy apps.
Here’s the thing, after a bit of research we were totally scared off. One of them even got written up in WP because it was sharing data with employers. As a home assistant user, I obviously like to keep things “In house” so to speak. I realized all these apps are doing is some basic math based on a due date and thought, “Why can’t I just do this in home assistant?” Anyway, turns out it wasn’t too hard.
It’s not perfect. For information I link to a couple of websites (VeryWell Family and What to Expect when You’re Expecting). So they still get to track me a bit when I visit their sites, but at the very least it should be less than the spooky apps.
Also, sorry about the references to “Download” we joked about the kid being a download and it sort of stuck, so some stuff says that.
(Image credit: https://whattoexpect.com/)
Input Datetime:
I used an input datetime to record the due date.
input_datetime:
due_date:
name: Pregnancy Due Date
has_date: true
has_time: false
Sensors:
sensor:
- platform: template
sensors:
pregnancy_days:
friendly_name: "Days until due"
unit_of_measurement: 'days'
value_template: "{{ (strptime(states.input_datetime.due_date.state, '%Y-%m-%d') - now().replace(tzinfo=None)).days }}"
pregnancy_weeks:
friendly_name: "Pregnancy Week"
unit_of_measurement: 'weeks'
value_template: "{{ ((40 - ((states.sensor.pregnancy_days.state | int) / 7)) | round(0, 'floor')) }}"
pregnancy_percent:
friendly_name: "Pregnancy Percent"
unit_of_measurement: '%'
value_template: "{{ ((280 - (states.sensor.pregnancy_days.state | int)) / 2.8) | round(0, 'floor')}}"
pregnancy:
friendly_name: "Pregnancy"
unit_of_measurement: 'Trimester'
value_template: |
{% set x = ((280 - (states.sensor.pregnancy_days.state | int)) / 93.3) | round(0, 'ceil') %}
{{ 'First' if x == 1 else 'Second' if x == 2 else 'Third' }}
attribute_templates:
days: "{{ states.sensor.pregnancy_days.state }}"
weeks: "{{ states.sensor.pregnancy_weeks.state }}"
trimester: "{{ ((280 - (states.sensor.pregnancy_days.state | int)) / 93.3) | round(0, 'ceil') }}"
months: "{{ ((280 - (states.sensor.pregnancy_days.state | int)) / 30.5) | round(1, 'half') }}"
percent: "{{ ((280 - (states.sensor.pregnancy_days.state | int)) / 2.8) | round(0, 'floor')}}"
what_to_expect_url: "https://www.whattoexpect.com/pregnancy/week-by-week/week-{{ states.sensor.pregnancy_weeks.state }}.aspx"
fetus_size_image: "https://images.agoramedia.com/wte3.0/gcms/wbw_squares_baby_wk_{{ states.sensor.pregnancy_weeks.state }}.jpg"
fetus_size_fruit_image: "https://images.agoramedia.com/wte3.0/gcms/wbw-{{ states.sensor.pregnancy_weeks.state }}-fruit.png"
fetus_size_fruit: |
{% set sizes = { 4: 'Strawberry Seed', 5: 'Orange Seed', 6: 'Sweet Pea', 7: 'Blueberry', 8: 'Raspberry',
9: 'Green Olive', 10: 'Prune', 11: 'Large Strawberry', 12: 'Lime', 13: 'Lemon',
14: 'Navel Orange', 15: 'Pear', 16: 'Avocado', 17: 'Large Onion', 18: 'Cucumber',
19: 'Mango', 20: 'Sweet Potato', 21: 'Large Banana', 22: 'Red Bell Pepper',
23: 'Grapefruit', 24: 'Pomegranate', 25: 'Eggplant', 26: 'Acorn Squash', 27: 'Cabbage',
28: 'Head of Lettuce', 29: 'Head of Cauliflower', 30: 'Bunch of Broccoli', 31: 'Coconut',
32: 'Cantaloupe', 33: 'Butternut Squash', 34: 'Pineapple', 35: 'Spaghetti Squash',
36: 'Bunch of Kale', 37: 'Canary Melon', 38: 'Mini Watermelon', 39: 'Honeydew Melon',
40: 'Small Pumpkin', 41: 'Pumpkin', 42: 'Watermelon' } %}
{{ sizes[([4, states('sensor.pregnancy_weeks')|int, 42]|sort)[1]] }}
verywellfamily_link: |
{% set pages = { 1: '4158813', 2: '4158819', 3: '4158839', 4: '4158847', 5: '4158868',
6: '4158911', 7: '4158916', 8: '4158920', 9: '4158922', 10: '4158926',
11: '4158930', 12: '4158934', 13: '4158941', 14: '4158944', 15: '4158988',
16: '4158998', 17: '4159005', 14: '4158944', 15: '4158988', 16: '4158998',
17: '4159005', 18: '4159009', 19: '4159012', 20: '4159017', 21: '4159022',
22: '4159032', 23: '4159036', 24: '4159040', 25: '4159047', 26: '4159097',
27: '4159102', 28: '4159110', 29: '4159140', 30: '4159146', 31: '4159202',
32: '4159205', 33: '4159211', 34: '4159227', 35: '4159237', 36: '4159243',
37: '4159250', 38: '4159251', 39: '4159263', 40: '4159264' } %}
{% set x = ([1, states('sensor.pregnancy_weeks')|int, 40]|sort)[1] %}
https://www.verywellfamily.com/{{x|string}}-weeks-pregnant-{{pages[x]}}
Input Numbers:
input_number:
pregnancy_week:
name: Pregnancy week persistent number
max: 42
min: 4
step: 1
mode: box
Automations:
# Use an input number to record the week updating so that it doesn't
# trigger on restart. This updates that (and notifies your phone with a link
# to the lovelace when it does!)
automation:
- id: pregnancy_week_updated
alias: 'Baby: Week Updated'
description: Triggered when the baby week changes
trigger:
- platform: template
value_template: >-
{{ (states('sensor.pregnancy_weeks') | int) >
(states('input_number.pregnancy_week') | int ) }}
condition: []
action:
- service: input_number.set_value
data:
entity_id: input_number.pregnancy_week
value: "{{ states('sensor.pregnancy_weeks') | int }}"
- service: notify.mobile_app_courtney_phone
data:
title: "It's Pregnancy week {{ states('sensor.pregnancy_weeks') }}!"
message: "Tap here to read all about what's up this week!"
data:
clickAction: /lovelace-pregnancy/baby
Lovelace:
Note: For the lovelace view I ended up using custom:text-element
and custom:card-templater
in order to get the image of “Fruit size” from “What to expect” to update.
title: Baby
path: baby
panel: false
badges: []
cards:
- type: 'custom:card-templater'
card:
type: picture-elements
image_template: '{{ states.sensor.pregnancy.attributes.fetus_size_fruit_image }}'
elements:
- type: state-label
entity: sensor.pregnancy
style:
font-size: 30px
top: 10%
left: 50%
- type: state-label
entity: sensor.pregnancy
prefix: 'It''s Week '
attribute: weeks
suffix: '!'
style:
font-size: 40px
top: 20%
left: 50%
- type: state-label
entity: sensor.pregnancy
prefix: '(That''s '
suffix: ' Months)'
attribute: months
style:
font-size: 20px
top: 29%
left: 50%
- type: 'custom:text-element'
text: The fetus is about
style:
font-size: 20px
top: 75%
left: 50%
- type: state-label
entity: sensor.pregnancy
prefix: 'the size of a '
attribute: fetus_size_fruit
suffix: '!'
style:
font-size: 20px
top: 82%
left: 50%
entities:
- sensor.pregnancy
- type: markdown
content: |
## [Read up from verywell Family]({{ states.sensor.pregnancy.attributes.verywellfamily_link }})
- type: markdown
content: |
## [Read up from "What to Expect"]({{ states.sensor.pregnancy.attributes.what_to_expect_url }})
- type: gauge
name: Download Status
entity: sensor.pregnancy_percent
min: 0
max: 100
severity:
green: 33
yellow: 67
red: 100
Edit: Thanks to @123 for the suggestion. Much neater!