River Flood Data from NOAA to Table and Graphical formats

I created a solution for folks whom may want river flood information in their dashboards. It all came from a question posted here:

I decided that the best solution for my needs was to extract the data from NOAA posted CSV files using curl to grab the data piped to jq raw to create targeted JSON with the information I need. The below example uses my specific river monitor, you can easily change to yours. The sensor is:

##
## water.weather.gov CSV
##
- platform: command_line
  scan_interval: 3600
  name: Russian River Flood Info
  command: "curl -s 'https://www.cnrfc.noaa.gov/graphicalRVF_csv.php?id=GUEC1' | jq --raw-input '{flooddata: [inputs | split(\",\") | {issued: .[0], valid: .[1] | strptime(\"%m/%d/%Y %I %p\") | strftime(\"%m/%d/%Y %I:%M %p\"), validts: .[1] | strptime(\"%m/%d/%Y %I %p\") | strftime(\"%Y-%d-%m %H:%M:%S\"), level: .[2] | tonumber, trend: .[3], status: .[4], mode: .[5] | gsub(\"[\\r]\"; \"\")  }]| .[2:999] }'"
  value_template: "{{ now() }}"
  json_attributes:
    - flooddata

This grabs the data from NOAA for GUEC1 in CSV format and then uses that jq command to structure it how I want it to be. The scan_interval is set to every hour because it is not needed more often than that and likely could be greater as they update data every 4 to 6 hours. The only real tricks employed here in jq is to parse NOAA date/times for charting purposes and excluding the first row of data as it is the header.

The result is like this:

So to put that data onto a dashboard, I chose to use custom:flex-table-card and custom:apexcharts-card. The YAML for these are:

type: custom:apexcharts-card
header:
  show: true
  title: Russian River Level
  standard_format: true
span:
  start: hour
  offset: '-2d'
experimental:
  color_threshold: true
  brush: true
brush:
  selection_span: 6d
now:
  show: true
update_delay: 3000ms
graph_span: 5d
series:
  - entity: sensor.russian_river_flood_info
    type: area
    stroke_width: 2
    data_generator: |-
      return entity.attributes.flooddata.map((point) => 
        { return [new Date(point.valid).getTime(), point.level]; });
    color_threshold:
      - value: 0
        color: '#3399ff'
      - value: 29
        color: '#3399ff'
      - value: 29
        color: '#e67300'
      - value: 32
        color: '#e67300'
      - value: 32
        color: '#cc3300'
      - value: 100
        color: '#cc3300'
    show:
      in_brush: true

type: custom:flex-table-card
entities:
  include: sensor.russian_river_flood_info
columns:
  - name: Date/Time
    data: flooddata
    modify: x.valid
  - name: Level
    data: flooddata
    modify: |-
      switch(x.status){
        case 'Above Monitor':
          '<div style="background-color:  #e67300;">' + parseFloat(x.level).toFixed(1) + '&nbsp;ft</div>';
          break;
        case 'Above Flood':
          '<div style="background-color: #cc0000;">' + parseFloat(x.level).toFixed(1) + '&nbsp;ft</div>';
          break;
        default:
          parseFloat(x.level).toFixed(1) + '&nbsp;ft';
        }
    align: center
  - name: Trend
    data: flooddata
    modify: |-
      switch(x.trend){
        case '+':
          '<ha-icon icon="mdi:arrow-up" style="color:  #e67300;">';
          break;
        case '-':
          '<ha-icon icon="mdi:arrow-down" style="color:  #3399ff;">';
          break;
        default:
          '<ha-icon icon="mdi:arrow-all">';
        }
    align: center
css:
  table+: 'padding: 0px'
card_mod:
  style: |
    ha-card {
      overflow: auto;
      max-height: 60vh;
    }

Only a few tricks employed to color cells based on flood level and replace trend with icons.

The final result is like this:

in the future I plan to expand this from NOAA to include rainfall and winds and eliminate other weather information as NOAA to me is the best source.

2 Likes

I just modified your example to suit my needs. About 3000 lines in sheets. Works great. Thanks for the direction.