Skip to content

Fix: RainViewer API now uses hash-based paths instead of timestamps #287

@Goldingr626

Description

@Goldingr626

Hi all,
My radar wasn't showing any data just a blank map. I used Claude AI to help me fix the issues.
I also had to make sure Zoom levels in the config file were 7 or smaller.
Hope this helps some people out.

Problem
RainViewer recently changed their API so that radar tile URLs no longer use timestamps as path identifiers. They now use hash-based paths. This causes all radar tiles to return HTTP 410 Gone, resulting in the base map displaying but no radar overlay.

Old URL format:
https://tilecache.rainviewer.com/v2/radar/1776633000/256/7/34/53/6/1_1.png
New URL format:
https://tilecache.rainviewer.com/v2/radar/b9ec619a3e33/256/7/34/53/6/1_1.png
The correct path hash is available from the RainViewer API:
https://api.rainviewer.com/public/weather-maps.json
Additional fixes included

VRB wind direction crash — METAR reports with variable (VRB) wind direction return None for wind_dir, causing a recurring AttributeError crash in wxfinished_metar every 30 minutes
Double slash in tile URLs — tile tails were prefixed with / causing malformed URLs like .../1776633000//256/...

Files changed
PyQtPiClock.py
Testing
Tested on Raspberry Pi running PiClock with Mapbox base maps and RainViewer radar overlay, located in Fort Pierce, Florida (KFPR).

Sure! Here's a clean step-by-step tutorial for fixing a fresh PiClock install.


PiClock Radar Fix Tutorial

Step 1 — Fix the wind direction crash

Open the file:

nano ~/PiClock/Clock/PyQtPiClock.py

Press Ctrl+W and search for:

wind_dir.compass

Find this code:

wd = f.wind_dir.compass()
        if Config.wind_degrees:
            wd = str(f.wind_dir.value) + u'°'

Replace it with:

if f.wind_dir is not None:
            wd = f.wind_dir.compass()
            if Config.wind_degrees:
                wd = str(f.wind_dir.value) + u'°'
        else:
            wd = 'VRB'

Step 2 — Fix the double slash in tile URLs

Still in the same file, press Ctrl+W and search for:

/256/%d/%d/%d/%d/%d_%d.png

Find this code:

tail = "/256/%d/%d/%d/%d/%d_%d.png" % (self.zoom, x, y,

Change it to (remove the leading slash):

tail = "256/%d/%d/%d/%d/%d_%d.png" % (self.zoom, x, y,

A few lines below, find:

tail = "/256/%d/%d/%d.png?color=%d" % (self.zoom, x, y,

Change it to:

tail = "256/%d/%d/%d.png?color=%d" % (self.zoom, x, y,

Step 3 — Fix the RainViewer API (hash-based paths)

Still in the same file, press Ctrl+W and search for:

def getTiles

Find this code:

    def getTiles(self, t, i=0):
        t = int(t / 600)*600
        self.getTime = t
        self.getIndex = i
        if i == 0:
            self.tileurls = []
            self.tileQimages = []
            for tt in self.tiletails:
                tileurl = "https://tilecache.rainviewer.com/v2/radar/%d/%s" \
                    % (t, tt)
                self.tileurls.append(tileurl)

Replace it with:

    def getTiles(self, t, i=0, path=None):
        t = int(t / 600)*600
        self.getTime = t
        self.getIndex = i
        if i == 0:
            if path is None:
                return
            self.tileurls = []
            self.tileQimages = []
            for tt in self.tiletails:
                tileurl = "https://tilecache.rainviewer.com%s/%s" \
                    % (path, tt)
                self.tileurls.append(tileurl)

Step 4 — Add the new fetchPathAndGetTiles method

Just above the def getTiles line, add this entire new method:

    def fetchPathAndGetTiles(self, t):
        import urllib2, json
        try:
            r = urllib2.urlopen("https://api.rainviewer.com/public/weather-maps.json")
            d = json.loads(r.read())
            for frame in d['radar']['past']:
                if frame['time'] == t:
                    self.getTiles(t, 0, frame['path'])
                    return
            past = d['radar']['past']
            if past:
                closest = min(past, key=lambda x: abs(x['time'] - t))
                self.getTiles(closest['time'], 0, closest['path'])
        except Exception as e:
            print "fetchPathAndGetTiles error: " + str(e)

Step 5 — Update the get() method to call the new function

Press Ctrl+W and search for:

self.getTiles(tt)

Find this code:

            if not gotit:
                self.getTiles(tt)
                break

Replace it with:

            if not gotit:
                self.fetchPathAndGetTiles(tt)
                break

Step 6 — Save and restart

Save with Ctrl+O, then exit with Ctrl+X.

Restart PiClock:

cd ~/PiClock
sh startup.sh

Radar should appear within 2-3 minutes as it builds up frames. Done!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions