Sounds like you ultimately want a “Time until next tide” value??? The tide_factor is a percent (tide_factor/100), so you could go (next_tide_time - last_tide_time) x tide_factor/100 to get an hours, minutes remaining result (if the tide is decreasing it becomes (1-tide_factor/100). Alternatively, next_tide_time - now() should also return the same result.
Everyone’s tide graphs look great, but since I mainly look at future tides rather than current ones, I built a tide prediction graph based off a customization of the NOAA data and the apexCharts-card for my own needs:
Welcome to the forum, and thanks for your contribution. Please be good enough to post your code
Yes but the factor represents the level of the tide so it would be a sign wave if plotted. This means the needle spends a lot of time near the high or low tide mark.
I want a clock the shows how many minutes until the next tide. So I still want a percentage but percentage of time until the next tide not the tide factor. This would be a linear measurement and look like a saw tooth if plotted.
I just want the percentage of time until the next tide.
The math in my code seems correct to generate this percentage it’s just not working.
Why use a percent then? Why not just compute (next_tide_time - now()) to get an hour/minute result?
Not OP, but here’s the code that will create an entity with the sine wave output for the graph.
- name: Tide Level Now
unique_id: tide_level_now
device_class: distance
unit_of_measurement: 'ft'
state: >-
{% set last_tide = states('sensor.last_tide_level') | float(0) %}
{% set tide_change = states('sensor.tide_change') | float(0) %}
{% set tide_factor = state_attr('sensor.tides', 'tide_factor') | float(0) %}
{% if is_state_attr('sensor.tides', 'next_tide_type', 'High') %}
{{ last_tide + (tide_change * (tide_factor / 100)) | abs | round(2) }}
{% else %}
{{ last_tide - (tide_change * (1 - tide_factor / 100)) | abs | round(2) }}
{% endif %}
icon: "{% if is_state_attr('sensor.tides', 'next_tide_type', 'High') %}mdi:arrow-top-right{% else %}mdi:arrow-bottom-right{% endif %}"
Here’s the output graph:
I am building an analog tide clock like the one the OP pictured. The time from high tide to low tide varies each day so the best way to build an analog dial is to set the dial to 100%. then you can use the math that has been used by several people in this thread to get the location of the pointer.
next_tide_time - now() then divide it by next_tide_time - last_tide_time to get the percentage.
The problem I’m having is the next_tide_time is returned as a text string not a time_t so I can’t get the math to work.
If I could just get this code to work it would do exactly what I want. But I’m not a programmer so I can’t fix this code.
- sensor:
- name: tide_pos
unit_of_measurement: "%"
state: >
{% set next_tide_datetime = strptime(state_attr('sensor.tides', 'next_tide_time'), "%I:%M %p") %}
{% set last_tide_datetime = strptime(state_attr('sensor.tides', 'last_tide_time'), "%I:%M %p") %}
{% set current_datetime = now() %}
{% if next_tide_datetime < last_tide_datetime %}
{% set next_tide_datetime = next_tide_datetime + timedelta(days=1) %}
{% endif %}
{% set total_interval = (next_tide_datetime - last_tide_datetime).total_seconds() %}
{% set elapsed_time = (current_datetime - last_tide_datetime).total_seconds() %}
{% if elapsed_time < 0 %}
{% set elapsed_time = elapsed_time + 86400 %}
{% endif %}
{% set percentage = (elapsed_time / total_interval) * 50 %}
{% if state_attr('sensor.tides', 'last_type') == "Low" %}
{% set percentage = percentage + 50 %}
{% endif %}
{{ percentage | float | round(2) }}
Yep, I realized after posting that you were after an analog solution, which I haven’t tried. Seems like the solution then ought to be to convert the next_tide_time from a string to a datetime object. I don’t have the exact syntax for that but its doable with some research.
In theory that is what the first few lines of my code should do.
The year on your next_tide and last_tide variables are defaulting to 1900. Unless you change those the elapsed time calc won’t work as intended.
Sounds like you may not be familiar with the template editor under developer tools?? It’s helpful to fix code issues. If it gives you an error and you don’t know which line is causing it, remove code lines until you ID which line is causing the error, then research that.
I’m not a programmer and more of a simple hacker. I don’t know how to use the template editor . That is very helpful thanks. It seems that the fork of NOAA we are using is not well suited for this type of math. If it returned more information it would be much better.
It looks like it won’t work in the next rev of Home Assistant anyway. I’ll see if I can get ChartGPT (that is how I code) to update the built in NOAA tide component to support next_tide and last_tide maybe I can have return time_t instead of just the time with no day component.
Its not really an integration vs. math thing here. More so, this is about data manipulation. You have a data element that you need to transform into a format that is more usable for your use case. HA supports this through templating which is the function of the code above. ChatGPT alone is frequently not “plug-n-playable”, but ChatGPT + the template editor, with enough trial an error testing, will probably get you where you need to go for a working version.
Yeah I got it working with a combination of the two
- sensor:
- name: tide_percent
unit_of_measurement: "%"
state: >
{% set next_tide_datetime = strptime(state_attr('sensor.tides', 'next_tide_time'), "%Y-%m-%dT%H:%M") %}
{% set last_tide_datetime = strptime(state_attr('sensor.tides', 'last_tide_time'), "%Y-%m-%dT%H:%M") %}
{% set current_datetime = now().replace(tzinfo=None) %}
{% set total_interval = (next_tide_datetime - last_tide_datetime).total_seconds() %}
{% set elapsed_time = (current_datetime - last_tide_datetime).total_seconds() %}
{% set percentage = (elapsed_time / total_interval) * 50 %}
{% if state_attr('sensor.tides', 'last_tide_type') == "Low" %}
{% set percentage = percentage + 50 %}
{% endif %}
{{ percentage | float | round(2) }}
I also needed to modify the NOAA component so that it send back time in a format with the month and year.
I just replaced %I:%M %p with %Y-%m-%dT%H:%M
Looks good for a base mockup. Now I just need to fancy it up a bit. Thanks so much for all your help.
Great, glad its working!
Seems like everybody on this thread is using the jshufro fork of NOAA tides because it has more features. But this fork no longer works with the latest version of Home Assistant.
And the author does not appear to be fixing it.
I put in a feature request to add this forks features to the built in NOAA tide component.
Please vote for my feature request and add any other comments that are useful to it.
Interesting thread. I did some work on this some time ago and ended up with a canvas gauge card that emulates a standard tide gauge. It’s got a few other features like overlaying wave heights (grey band) and the critical depth (in pink) needed for launching one of our lifeboats.
Heads up. There is a pull request for the jshufro/home_assistant_noaa_tides repository that fixes the problems that broke the integration with 2025.1 (Thank You Flight-Lab!)
It does appear that the original developer is not supporting the repository any longer, and no new releases have come out for a while. There are a couple Pull Requests now that have not been reviewed and/or merged into the project. Long term, forking this code into a new supported repository would be great. In the meantime, the basic features that I have been using are working again with Flight-Lab’s changes.
This is EXACTLY what I’m tring to do!
But having LOTS of trouble doing it. I’m in Australia so can’t use NOAA for tide data, however I’m using the stormglass.io tide API which is outputting data to a sensor (call it tide_height_by_hour) as a “state attribute” which comes up as follows:
data:
- sg: 0.46
time: “2025-01-06T00:00:00+00:00” - sg: 0.33
time: “2025-01-06T01:00:00+00:00” - sg: 0.22
time: “2025-01-06T02:00:00+00:00”
etc etc (for every hour for the next few days)
I can’t for the life of me work out how to convert this into a sensor that I can put into a graph going forward.
I’ve love any advice or suggestions. Thanks so much!
I also don’t have a sensor, and the data is very similar to your format! ApexCharts supports data manipulation, which worked well for this. Here’s what a similar graph card might look like for yours (just replace your_state_attribute_name
with the actual list attribute name):
type: custom:apexcharts-card
graph_span: 135h
header:
show: true
title: My Title
show_states: false
span:
start: minute
series:
- entity: sensor.tide_height_by_hour
name: Height (ft)
extend_to: end
type: line
data_generator: >
return entity.attributes.your_state_attribute_name.map((prediction) => { return[new
Date(prediction.time), prediction.sg]; });