ESPHome tide clock

I want to build a graphic tide clock using LVGL. I easily build a gauges that spins 360 degrees with high tide at the top and low at the bottom.

I just need the time of the previous high tide and the next high tide and then divide that time by 360 degrees

This API call can get the high an low tides from a 72 hour range.

https://api.tidesandcurrents.noaa.gov/api/prod/datagetter?station=8454578&product=predictions&datum=MLLW&time_zone=lst_ldt&units=english&interval=hilo&format=json&begin_date=20241209&range=72

I just need some code to parse through the JSON and get the last and next high tide based on the current time.

Looks like there is already way to do this but the lambda is beyond my skill level.

Can anybody help me with this?

Use one of the tide integrations in home assistant and import the sensors into esphome.

Yes it’s easy to get the hi/lo tide times from both this API or home assistant but it’s calculating the angle of the analog tide clock that I can’t figure out how to do.

Take a look here Tides in Lovelace - #11 by nickrout. This is in Lovelace, but might give you some ideas.

I ended up needing to build a component that can calculate the tide a a percentage. So for example if the tide is half way between high and low the percentage is 25%. That way I can just have a meter that measures from 1 to 100. I did this by customizing the NOAA tide Home Assistant component.

I just need to add a bit of color and “fancy it up” a bit. But it’s working well.

Screenshot 2025-01-14 003304

1 Like
substitutions:
  name: "tideclock"
  friendly_name: "tide clock"
  device_description: "Simple tide clock"
  text_font: roboto24

esphome:
  name: tideclock
  friendly_name: "Tide Clock"

external_components:
  - source: github://pr#8005
    components: [lvgl]

host:
  mac_address: "62:23:45:AF:B3:01"
  
touchscreen:  
  - platform: sdl
    id: my_touchscreen
    display: my_display

display:
  - platform: sdl
    id: my_display
    update_interval: never
    auto_clear_enabled: false
    dimensions:
      width: 480
      height: 480  

api:
logger:
time:
  - platform: homeassistant
    id: system_time

text_sensor:
  - platform: homeassistant
    entity_id: sensor.tides
    attribute: tide_percentage
    id: tide_percentage
    on_value:
      then: 
        - lvgl.indicator.update:
            id: tide_level
            value: !lambda |-
              return std::stof(id(tide_percentage).state);

  - platform: homeassistant
    entity_id: sensor.tides
    attribute: next_tide_type
    id: next_tide_type
    
  - platform: homeassistant
    entity_id: sensor.tides
    attribute: next_tide_time
    id: next_tide_time
    on_value:
      - if:
          condition:
            text_sensor.state:
              id: next_tide_type
              state: 'Low'
          then:
            - lvgl.label.update:
                id: low_tide_label
                text:
                   format: "%s"                  
                   args: [ 'id(next_tide_time).state.c_str()' ]
          else:
            - lvgl.label.update:
                id: high_tide_label
                text:
                   format: "%s"                
                   args: [ 'id(next_tide_time).state.c_str()' ]

  - platform: homeassistant
    entity_id: sensor.tides
    attribute: last_tide_type
    id: last_tide_type
    
  - platform: homeassistant
    entity_id: sensor.tides
    attribute: last_tide_time
    id: last_tide_time
    on_value:
      - if:
          condition:
            text_sensor.state:
              id: last_tide_type
              state: 'Low'
          then:
            - lvgl.label.update:
                id: low_tide_label
                text:
                   format: "%s"                  
                   args: [ 'id(last_tide_time).state.c_str()' ]
          else:
            - lvgl.label.update:
                id: high_tide_label
                text:
                   format: "%s"                
                   args: [ 'id(last_tide_time).state.c_str()' ]

# -------------------------------------------
# LVGL Buttons
# -------------------------------------------
lvgl:
  displays: 
    - my_display
  touchscreens:
    - my_touchscreen
     
  theme:
    obj:
      radius: 0
      border_width: 0
      pad_all: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    label:
      radius: 0    
      border_width: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    image:
      radius: 0    
      border_width: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red
    meter:
      border_width: 0
      pad_all: 0
      scrollable: false
#      outline_width: 1
#      outline_color: red

  page_wrap: true
  
  pages:
      - id: main_page
        width: 100%
        bg_color: Black
        align: center
        widgets:
          - obj:
              height: 480
              width: 480
#              layout: 
#                type: flex
#                pad_row: 0
              bg_color: White
              align: center
              pad_all: 4
              widgets:
                - meter:
                    height: 100%
                    width: 100%
                    text_font: roboto24
                    outline_width: 1
                    scales:
                        - range_from: 1
                          range_to: 100
                          angle_range: 360
                          rotation: 270
                          indicators:
                            - image:
                                id: tide_level
                                src: tide_pointer
                                pivot_x: 44
                                pivot_y: 44
                                value: 0
                          ticks:
                            count: 0
                        - range_from: 5
                          range_to: 1
                          angle_range: 120
                          rotation: 300
                          ticks:
                            width: 1
                            count: 5
                            major:
                              label_gap: 25
                              stride: 1
                              width: 2
                              length: 20
                        - range_from: 5
                          range_to: 1
                          angle_range: 120
                          rotation: 120
                          ticks:
                            width: 1
                            count: 5
                            major:
                              label_gap: 25
                              stride: 1
                              width: 2
                              length: 20                              

                - label:
                    align: center
                    width: 100%
                    text_align: center
                    text_font: roboto24
                    text: "High Tide"
                    y: -215              
                - label:
                    id: high_tide_label
                    align: center
                    width: 100%                    
                    text_align: center
                    text_font: roboto24
                    text: "00:00 am"
                    y: -185                 
                - label:
                    align: center
                    width: 100%
                    text_align: center
                    text_font: roboto24
                    text: "Low Tide"
                    y: 215                   
                - label:
                    id: low_tide_label
                    align: center
                    width: 100%                    
                    text_align: center
                    text_font: roboto24
                    text: "00:00 am"
                    y: 185  

# -------------------------------------------
# Graphics and Fonts
# -------------------------------------------
image:
  - file: assets/tide_pointer.svg
    id: tide_pointer
    resize: 200x88 # 2.272  - 22x22
    type: RGB565
    use_transparency: true  
    
font:
  - file: "gfonts://Roboto"
    id: roboto24
    size: 24
    bpp: 8

1 Like