It is currently December 7th, 2023, 5:12 pm

Tiny Weather Animated

Weather skins
User avatar
xenium
Posts: 822
Joined: January 4th, 2018, 9:52 pm

Tiny Weather Animated

Post by xenium »

TinyW2022-2.PNG
Version 2022



.....more details on the download page





Download: https://www.deviantart.com/xenium-art/art/Tiny-Weather-Animated-939250053
You do not have the required permissions to view the files attached to this post.
Last edited by xenium on November 30th, 2022, 10:10 pm, edited 1 time in total.
User avatar
xenium
Posts: 822
Joined: January 4th, 2018, 9:52 pm

Re: Tiny Weather Animated

Post by xenium »

30-NOV-2022
The skin has been updated
User avatar
xenium
Posts: 822
Joined: January 4th, 2018, 9:52 pm

Re: Tiny Weather Animated

Post by xenium »

1-SEP-2023
The skin has been updated
User avatar
nek
Posts: 100
Joined: November 3rd, 2019, 12:00 am

Re: Tiny Weather Animated

Post by nek »

First of all, sorry for disturbing the topic, but I have something to share I have learnt before.



1. m/s (meters per second) for WIND SPEED

(1) Units for Wind Speed
wind_speed_europe.png
Image file from: Units for wind speed in Europe (reddit.com)

m/s is used for wind speed in Japan (ja-JP), Taiwan (zh-TW) and China (zh-CN).



(2) Weather.com api request parameter and response

Weather.com api support m/s for wind speed with http request query parameter units=s
twc_api_res.png
@see
International System of Units (Wikipedia)


Announcement wrote:
Skin Authors: openstreetmap usage

Too many http requests to nominatim.openstreetmap.org from Rainmeter skins, need to be fixed.



The below is for optimizing the skin code.
package: tiny_weather_animated__updated_1_sep_2023__by_xenium_art_dfj7dz9.rmskin




2. WebParser RegExp option

(1) Better syntax of regular expression

TinyWeather\@Resources\Measures.inc

Code: Select all

[WEATHER.COMSuperParent]
Measure=WebParser
; RegExp=(?siU)^(.*)$
RegExp=(?s)^(.*)$
RegExp=(?s)^(.*)$ is much better for getting a whole string. (?siU) is used when you need to get a part of contents.

(?siU)^(.*)$ 35857 steps (regex101.com)
(?s)^(.*)$ 7 steps (regex101.com)

@description Regular expression
^ Beginning of the string
$ End of the string

@description about (?siU)
s modifier: single line. Dot . matches newline characters
i modifier: insensitive. Case insensitive match (ignores case of [a-zA-Z])
U modifier: Ungreedy. The match becomes lazy by default. Now a ? following a quantifier makes it greedy

(?U).+ and .+? are ungreedy (lazy), .+ and (?U).+? are greedy.

Tips: regex101 settings for WebParser measure RegExp option
FLAVOR: PCRE (PHP <7.3), FUNCTION: Match, REGEX FLAGS: none | https://regex101.com/r/AZUNvH/4

Tips: We can see the regular expression parsing process step by step.
TOOLS > 🐞Regex Debugger (bottom left of the page on the regex101.com)

@see
WebParser RegExp, PCRE Regex Cheatsheet
3. Regular Expression Flags (?i)

TinyWeather\TinyWeather.ini

Code: Select all

[MeasureSetCounter]
Measure=String
IfMatch=(?i)0
...
i modifier: insensitive. Case insensitive match (ignores case of [a-zA-Z])

Not for a number.
4. Measure IfMatch option

(1) Usage of IfMatch option

TinyWeather\TinyWeather.ini

Code: Select all

[MeasureSetCounter]
Measure=String
String=[MeasureIcon]
IfMatch=(?i)0
IfMatchAction=[...]
IfMatch2=(?i)1
IfMatchAction2=[...]
IfMatch3=(?i)2
IfMatchAction3=[...]
IfMatch4=(?i)3
IfMatchAction4=[...]
IfMatch5=(?i)4
IfMatchAction5=[...]
IfMatch6=(?i)5
IfMatchAction6=[...]
...
IfMatch48=(?i)47
IfMatchAction48=[...]
IfMatch option behaves different from if ... elseif ... elseif ... elseif ... end,
It is something like if ... end. if ... end. if ... end. if ... end. ...
For instance, if the string value is 15, it matches 1 and IfMatchAction2 will be performed, then it matches 5 and IfMatchAction6 will be performed. Finally it will match 15.


An example code of [MeasureSetCounter]

Code: Select all

[MeasureSetCounter]
Measure=String
Group=Counters
String=[MeasureIcon]
DynamicVariables=1
Disabled=1
UpdateDivider=-1
IfMatchMode=1
IfMatch=^
IfMatchAction=[!SetOption MeasureCounter Formula "Counter % 28"]
IfMatch2=^(?:19|20|21|22)$
IfMatchAction2=[!SetOption MeasureCounter Formula "Counter % 90"]
IfMatch3=^26$
IfMatchAction3=[!SetOption MeasureCounter Formula "Counter % 46"]
IfMatch4=^44$
IfMatchAction4=[!SetOption MeasureCounter Formula "Counter % 1"]
IfMatch=^ always return true, even if the string value is blank (empty string).
IfMatchAction will be performed first, then evaluate the IfMatch2=, IfMatch3=, IfMatch4= on the [MeasureSetCounter] measure updating.

@description Regular expression
^ Beginning of the string
$ End of the string
(?:...) non-capturing group. (?:AB|CD|EF) AB or CD or EF

@see
Measure IfMatch, Measure IfMatchMode, PCRE Regex Cheatsheet
5. [Rainmeter] DefaultUpdateDivider=-1 option
nek wrote:
Purpose of this chapter
◾ Learn what UpdateDivider and DefaultUpdateDivider are. (Refer to the description below)
◾ Learn what steps are taken during the Update cycle of a skin in Rainmeter. (⭐ How a skin is updated)
◾ Minimize the number of measures/meters those are updating in the skin update cycle, to reduce the Rainmeter.exe 's workload.
core_measure_ud.png
Left side: Normal Rainmeter skin.
Right side: Optimized Rainmeter skin. Set DefaultUpdateDivider=-1 on the [Rainmeter] and set UpdateDivider=1 on the Core Measures.

For TinyWeather skin, Core Measure are WebParser measure (weather data) and Calc:Counter measure (animation).

Rainmeter Documentation wrote:
UpdateDivider (default: 1) - Measure and Meter option
Frequency at which the measure/meter is updated. The Update option in the [Rainmeter] section of the skin is multiplied by the specified value to determine how often the measure/meter is updated.
Example: If Update=1000 (in the [Rainmeter] section) and UpdateDivider=30, the measure/meter is updated every 30 seconds.
If UpdateDivider=-1 or any negative number, then the measure/meter is only updated once when the skin is loaded or refreshed.

DefaultUpdateDivider (default: 1) - [Rainmeter] section option
This option is designed to set a default UpdateDivider for all measures and meters in the skin. It can be overridden by setting UpdateDivider on individual measures or meters.


(1) Set DefaultUpdateDivider=-1 option on the [Rainmeter]

TinyWeather\TinyWeather.ini

Code: Select all

[Rainmeter]
Update=60
BackgroundMode=2
SolidColor=0,0,0,1

; DynamicWindowSize=1
DefaultUpdateDivider=-1
Update=60 option is set for the smooth Animation (16 fps) of the weather icon.
Using DefaultUpdateDivider=-1 option on the [Rainmeter] section is recommended.

@see
[Rainmeter] DynamicWindowSize, [Rainmeter] DefaultUpdateDivider, Measure UpdateDivider
nek wrote:
Off Topic An example code for normal weather skins as a first step.

Code: Select all

[Rainmeter]
Update=60000
DefaultUpdateDivider=-1
AccurateText=1

[sWebParser]
Measure=WebParser
URL=
UpdateDivider=1
UpdateRate=15
Flags=Resync | NoCookies
Header=DNT: 1
Header2=Sec-GPC: 1
Header3=Connection: close
UserAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0
FinishAction=...[!UpdateMeter *][!Redraw]
The WebParser accesses and parses the remote resource every 15 minutes.

@see
WebParser measure
HTTP header Connection (MDN Web Docs), Latest Web Browser User Agents (whatismybrowser.com)


(2) Set UpdateDivider=1 option on the [MeasureCounter] (Calc: Counter)

TinyWeather\TinyWeather.ini

Code: Select all

[MeasureCounter]
Measure=Calc
Group=Counters
Disabled=1

UpdateDivider=1
OnChangeAction=[!UpdateMeter MeterIcon]
@see
Measure UpdateDivider, Measure OnChangeAction, Calc measure Counter



(3) Set UpdateDivider=1 option on the [WEATHER.COMSuperParent] (WebParser)

TinyWeather\@Resources\Measures.inc

Code: Select all

[WEATHER.COMSuperParent]
Measure=WebParser
URL=#URL#
UpdateRate=10000
Flags=Resync | NoCookies
DecodeCharacterReference=1
LogSubstringErrors=0
StringIndex=1

Header=Connection: close
UpdateDivider=1
; RegExp=(?siU)^(.*)$
RegExp=(?s)^(.*)$
; UserAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0
UserAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0
; FinishAction=[!EnableMeasureGroup Parents]
FinishAction=[!EnableMeasureGroup Parents][!UpdateMeter *][!Redraw]
Accesses and parses the remote resource every 10 minutes. (= 600 seconds = 600000 milliseconds)
[Rainmeter] Update=60 * [WEATHER.COMSuperParent] UpdateDivider=1 * UpdateRate=10000

@see
WebParser FinishAction, WebParser: How UpdateRate Works
HTTP header Connection (MDN Web Docs), Latest Web Browser User Agents (whatismybrowser.com)



(4) Append [MeasureToggleAtNight] measure

TinyWeather\@Resources\Measures.inc

Code: Select all

[MeasureToggleAtNight]
Measure=String
String=[MeasureDailyPrecipDay1]
DynamicVariables=1
IfMatchMode=1
IfMatch=^$
IfMatchAction=[!UpdateMeasure MeasureDailyPrecipDay1]
Disabled=1
Dealing with empty data of the day. If [MeasureDailyPrecipDay1] value is empty, [MeasureDailyPrecipNight1] value will be used.

Code: Select all

[WEATHER.COMSuperParent]
; FinishAction=[!EnableMeasureGroup Parents]
; FinishAction=[!EnableMeasureGroup Parents][!UpdateMeter *][!Redraw]
FinishAction=[!EnableMeasureGroup Parents][!EnableMeasure MeasureToggleAtNight][!UpdateMeasure MeasureToggleAtNight][!UpdateMeter *][!Redraw]
nek wrote:
Off Topic
All measure and meter have some tasks during updating itself. (⭐ How a skin is updated)
You can see how often the measures/meters are updating in one second for debugging purpose.
Adding the following code and save then refresh the skin, open About Rainmeter window > Log tab

Code: Select all

[MeasureName/MeterName]
UpdateDivider=1
OnUpdateAction=[!Log "#CURRENTSECTION# | Update" warning]

@see
How a skin is updated by jsmorley
💡 Reducing a cpu and memory usage of a skin by nek



The below is additional optimization.
If you would like to keep a compatibility with jsmorley's WeatherComJSON package, these might not nesessary.




6. Weather.com api request query parameters

(1) Request an only needed data by the skin

TinyWeather\@Resources\Variables.inc

Code: Select all

URL=...
Changed: from v3-wx-forecast-daily-15day to v3-wx-forecast-daily-3day
Removed: v3alertsHeadlines and v3-wx-forecast-hourly-12hour

Response data: json file size: from 17 KB to 6 KB
The weather.com services have millions of api requests per second, I guess. We need to keep skins to be gentle to the servers.


(2) Modify the regular expressions

TinyWeather\@Resources\RegExp.inc

Code: Select all

; DailyForecastTempMax=(?siU)"v3-wx-forecast-daily-15day":.*{.*"temperatureMax":(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),.*
DailyForecastTempMax=(?siU)"v3-wx-forecast-daily-3day":.*{.*"temperatureMax":(.*),

; DailyForecastTempMin=(?siU)"v3-wx-forecast-daily-15day":.*{.*"temperatureMin":(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),.*
DailyForecastTempMin=(?siU)"v3-wx-forecast-daily-3day":.*{.*"temperatureMin":(.*),

; DailyForecastPrecip=(?siU)"v3-wx-forecast-daily-15day":.*{.*"precipChance":(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),.*
DailyForecastPrecip=(?siU)"v3-wx-forecast-daily-3day":.*{.*"precipChance":(.*),(.*),
7. WebParser RegExp option again

(1) Change RegExp= code (non-capturing) and remove StringIndex=1

TinyWeather\@Resources\Measures.inc

Code: Select all

[WEATHER.COMSuperParent]
Measure=WebParser
; RegExp=(?s)^(.*)$
; RegExp=(?s)^.*$
RegExp=\A[\s\S]*\z
; StringIndex=1
When getting a whole string of remote contents, there is no need to capture with (), since the WebParser has already had the whole string data. (About Rainmeter > Skins > TinyWeather > WEATHER.COMSuperParent : String value).
You might use RegExp=\A[\s\S]*\z or RegExp=(?s)^.*$.

@description
(?s) modifier: single line. Dot . matches newline characters
^ Beginning of the string
$ End of the string
\A Very beginning of the string
\z Very end of the string
\s Whitespace characters [\r\n\t\f\v ]
\S Non-whitespace characters [^\r\n\t\f\v ]

[\s\S]* is equivalent to (?s).*

@see
PCRE Regex Cheatsheet



(2) Remove StringIndex=1 from [WEATHER.COMSuperParent] 's child measures

Code: Select all

[MeasureLocation]
Measure=WebParser
Group=Parents
URL=[WEATHER.COMSuperParent]
Disabled=1
; StringIndex=1
RegExp=#Location#
LogSubstringErrors=0
[MeasureCurrentObservations], [MeasureDailyForecastTempMax],
[MeasureDailyForecastTempMin], [MeasureDailyForecastPrecip]

@see
WebParser StringIndex



Final code

📦 TinyWeather.Optimized.2023-11-27.zip (11.3 MB, GitHub.com)

Modified files
TinyWeather\TinyWeather.ini
TinyWeather\@Resources\Measures.inc
TinyWeather\@Resources\RegExp.inc
TinyWeather\@Resources\Variables.inc

Note that this is one of the examples of optimizing Rainmeter skin code.
TinyWeather\Language\Language.ini file is not modified. You might apply units=s (m/s for wind speed) related things if you like.






Announcement wrote:
Skin Authors: openstreetmap usage

Too many http requests to nominatim.openstreetmap.org from Rainmeter skins, need to be fixed.
You do not have the required permissions to view the files attached to this post.
Last edited by nek on December 3rd, 2023, 4:48 pm, edited 6 times in total.
User avatar
Yincognito
Rainmeter Sage
Posts: 6406
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Tiny Weather Animated

Post by Yincognito »

I won't touch the suggestions above (by the way, I'm one of the first, if not one of the few who, ever since I created my suite, only updated the weather once an hour as it's not changing every minute, and not using nominatim at all since it's no big deal to look for your geocode online on wiki), but just so folks know, that measurement units map linked above is not exactly accurate in practice, things are more consistent over the continent in that regard...
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth