-
-
Save Surendrajat/ff3876fd2166dd86fb71180f4e9342d7 to your computer and use it in GitHub Desktop.
"custom/weather": { | |
"exec": "python ~/.config/waybar/scripts/weather.py", | |
"restart-interval": 300, | |
"return-type": "json", | |
"on-click": "xdg-open https://weather.com/en-IN/weather/today/l/$(location_id)" | |
// "format-alt": "{alt}", | |
}, |
#custom-weather.severe { | |
color: #eb937d; | |
} | |
#custom-weather.sunnyDay { | |
color: #c2ca76; | |
} | |
#custom-weather.clearNight { | |
color: #2b2b2a; | |
} | |
#custom-weather.cloudyFoggyDay, #custom-weather.cloudyFoggyNight { | |
color: #c2ddda; | |
} | |
#custom-weather.rainyDay, #custom-weather.rainyNight { | |
color: #5aaca5; | |
} | |
#custom-weather.snowyIcyDay, #custom-weather.snowyIcyNight { | |
color: #d6e7e5; | |
} | |
#custom-weather.default { | |
color: #dbd9d8; | |
} |
#!/usr/bin/env python3 | |
from pyquery import PyQuery # install using `pip install pyquery` | |
import json | |
################################### CONFIGURATION ################################### | |
# set your location_id | |
# to get your location_id, go to https://weather.com & search for your location. | |
# once you choose your location, you can see the location_id in the URL(64 chars long hex string) | |
# like this: https://weather.com/en-IN/weather/today/l/c3e96d6cc4965fc54f88296b54449571c4107c73b9638c16aafc83575b4ddf2e | |
# once you get the location_id, you can replace the below location_id with your own location_id | |
location_id = "c3e96d6cc4965fc54f88296b54449571c4107c73b9638c16aafc83575b4ddf2e" # TODO | |
# celcius or fahrenheit | |
unit = "metric" # metric or imperial | |
# forcase type | |
forecast_type = "Daily" # Hourly or Daily | |
########################################## MAIN ################################## | |
# weather icons | |
weather_icons = { | |
"sunnyDay": "滛", | |
"clearNight": "望", | |
"cloudyFoggyDay": "", | |
"cloudyFoggyNight": "", | |
"rainyDay": "", | |
"rainyNight": "", | |
"snowyIcyDay": "", | |
"snowyIcyNight": "", | |
"severe": "", | |
"default": "", | |
} | |
# get html page | |
_l = "en-IN" if unit == "metric" else "en-US" | |
url = f"https://weather.com/{_l}/weather/today/l/{location_id}" | |
# get html data | |
html_data = PyQuery(url=url) | |
# current temperature | |
temp = html_data("span[data-testid='TemperatureValue']").eq(0).text() | |
# current status phrase | |
status = html_data("div[data-testid='wxPhrase']").text() | |
status = f"{status[:16]}.." if len(status) > 17 else status | |
# status code | |
status_code_class = html_data("#regionHeader").attr("class") | |
status_code = str(status_code_class).split(" ")[2].split("-")[2] | |
# status icon | |
icon = ( | |
weather_icons[status_code] | |
if status_code in weather_icons | |
else weather_icons["default"] | |
) | |
# temperature feels like | |
temp_feel = html_data( | |
"div[data-testid='FeelsLikeSection'] > span > span[data-testid='TemperatureValue']" | |
).text() | |
temp_feel_text = f"Feels like {temp_feel}{'c' if unit == 'metric' else 'f'}" | |
# min-max temperature | |
temp_min = ( | |
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']") | |
.eq(1) | |
.text() | |
) | |
temp_max = ( | |
html_data("div[data-testid='wxData'] > span[data-testid='TemperatureValue']") | |
.eq(0) | |
.text() | |
) | |
temp_min_max = f" {temp_min}\t\t {temp_max}" | |
# wind speed | |
wind_speed = str(html_data("span[data-testid='Wind']").text()) | |
wind_text = f"煮 {wind_speed}" | |
# humidity | |
humidity = html_data("span[data-testid='PercentageValue']").text() | |
humidity_text = f" {humidity}" | |
# visibility | |
visbility = html_data("span[data-testid='VisibilityValue']").text() | |
visbility_text = f" {visbility}" | |
# air quality index | |
air_quality_index = html_data("text[data-testid='DonutChartValue']").text() | |
# rain prediction | |
r_prediction_text = html_data(f"section[aria-label='{forecast_type} Forecast']")( | |
"div[data-testid='SegmentPrecipPercentage'] > span" | |
).text() | |
r_prediction = str(r_prediction_text).replace("Chance of Rain", "") | |
r_prediction = f" ({forecast_type}) {r_prediction}" if len(r_prediction) > 0 else r_prediction | |
# temperature prediction | |
t_prediction_text = html_data(f"section[aria-label='{forecast_type} Forecast']")( | |
"div[data-testid='SegmentHighTemp'] > span" | |
).text() | |
t_prediction = str(t_prediction_text).replace(" /", "/") | |
t_prediction = f" 滛 ({forecast_type}) {t_prediction}" if len(t_prediction) > 0 else t_prediction | |
#pretty print all data | |
# print(f"temp: {temp}\nstatus: {status}\nstatus_code: {status_code}\nicon: {icon}\ | |
# \ntemp_feel_text: {temp_feel_text}\ntemp_min_max: {temp_min_max}\nwind_text: {wind_text}\ | |
# \nhumidity_text: {humidity_text}\nvisbility_text: {visbility_text}\nair_quality_index: {air_quality_index}\ | |
# \nprediction: \n{r_prediction}\n{t_prediction}") | |
# tooltip text | |
tooltip_text = str.format( | |
"\t\t{}\t\t\n{}\n{}\n{}\n\n{}\n{}\n{}\n\n{}\n{}", | |
f'<span size="xx-large">{temp}</span>', | |
f"<big>{icon}</big>", | |
f"<big>{status}</big>", | |
f"<small>{temp_feel_text}</small>", | |
f"<big>{temp_min_max}</big>", | |
f"{wind_text}\t{humidity_text}", | |
f"{visbility_text}\tAQI {air_quality_index}", | |
f"<i>{r_prediction}</i>", | |
f"<i>{t_prediction}</i>" | |
) | |
# print waybar module data | |
out_data = { | |
"text": f"{icon} {temp}", | |
"alt": status, | |
"tooltip": tooltip_text, | |
"class": status_code, | |
} | |
print(json.dumps(out_data)) |
I got an update on the fetching logic, also discussed further above.
The correct synthax is now
# get html page
url = "https://weather.com/en-IN/weather/today/l/" + location_id
html_data = PyQuery(url=url)
Updates on what args PyQuery takes can be found here: https://pyquery.readthedocs.io/en/latest/scrap.html (as also posted further above by @cn-danieldev.)
As of date of this comment I can confirm that this script still works!
Is it possible to get Fahrenheit? I notice there is no separate URL for Fahrenheit on the website, guess some JS handling or something.
Possible to get 5-day?
When I click the popup/dropdown thing, goes to 404 page: https://weather.com/en-IN/weather/today/l/
ie. missing location_id at that point.
To get English/Imperial units append '?units=e' to the end of your location_id. My locations looks like this:
location_id = "ff02642ddd763393bf9158589c1b4804cc84c808136cc42554efce2a92fc47fb?unit=e" # appending '?unit=e' changes everything to English/Imperial units
Here is what my screen looks like, yes I made a few other minor mods to the file since I don't know/understand any Asian characters.
I hope you, and others, find this helpful.
Hello, while I did write my own CSS for this, I did notice a typo in your CSS. In your CSS you have:
#custom-weather.showyIcyDay, #custom-weather.snowyIcyNight { color: #d6e7e5; }
It should say:
#custom-weather.snowyIcyDay, #custom-weather.snowyIcyNight { color: #d6e7e5; }
I noticed it when I started with your CSS sheet and wanted to have different appearances for Day and Night. By the way, I love the script and the lack of need to sign up for any additional APIs. It is simple, looks great, and it works.
Can someone please demonstrate how to get the wind direction?
First, I really like this module. One question. On mine I find a slight misalignment just under "feels like". One measurement seems to be too far over to the right. Is there a way I can correct this in the py file?
edit: Nevermind, I fixed it. Turns out just removing the big tag around min-max fixes that. Also the min and max temps were reversed. Fixed that too. I have no idea what font you were using but I had to change all the weather icons to work with Jet Brains NF.
Triple posting rebel I am. I just noticed that the max temperature now no longer works. After looking at the source code on weather.com I did find it again just one entry after the current temp. I adjusted my min and max settings. I'm no longer looking at what division it's in, just following the order I saw the different temps being mentioned:
# min-max temperature
temp_min = html_data("span[data-testid='TemperatureValue']").eq(2).text()
temp_max = html_data("span[data-testid='TemperatureValue']").eq(1).text()
Thanks everyone for keeping it alive while I was in jail(jk.. was def not..). Anyway I've updated the script with suggested fixes and a configuration section for common requests.
Thanks @alzalia1 @SeanEParsons @tdtooke for looking into it.
Is it possible to get Fahrenheit?... Possible to get 5-day?
@chrisco23 both possible now. Please check the config section.
which font u use for weather icon
@DoYouSeeAmin I use JetBrainsMono Nerd Font
Can someone please demonstrate how to get the wind direction?
@XenBuddha you can look into Wind--windWrapper
class (specifically the highlighted property). It will give you rotation in degrees.

I'm currently using macOS for work so haven't tested end-to-end. Let me know if you find any issues.
Can someone please demonstrate how to get the wind direction?
@XenBuddha you can look into
Wind--windWrapper
class (specifically the highlighted property). It will give you rotation in degrees.I'm currently using macOS for work so haven't tested end-to-end. Let me know if you find any issues.
Thanks for your response. While I appreciate your response, this code isn't helpful to me. Any chance you could add the wind direction? The pointing arrow is preferable as it is the most concise. It seems to be the only major element missing from the script. Kr
When trying to run the script, I get the following message:
Traceback (most recent call last):
File "/home/glmachado/.config/waybar/weather.py", line 79, in
wind_speed = html_data("span[data-testid='Wind']").text().split("\n")[1]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range
It used to work just fine until yesterday.
which font u use for weather icon