It is currently March 29th, 2024, 2:15 pm

WebSocket Client Plugin

Share and get help with Plugins and Addons
Likon
Posts: 6
Joined: September 2nd, 2018, 9:19 pm

WebSocket Client Plugin

Post by Likon »

A plugin for Rainmeter that implements a WebSocket client.
Can be used to communicate with other programs, webpages or any device that hosts a WebSocket server.

Measure Options:
  • Address - address and port of the server to connect to
  • OnOpen - bang to execute when connection is estabilished
  • OnClose - bang to execute when connection is closed
    Note: $message$ keyword will be replaced by the content of the closing message received
  • OnMessage - bang to execute when a message is received from server
    Note: $message$ keyword will be replaced by the content of the message received
  • KeepAlive - 1 or 0 - if active will try to reconnect to the server if the connection is lost or is not achieved on the first try
  • MaxReconnectAttempts - number of times it will try to reconnect before completly stopping
    Note: if the number is 0 then it will keep trying to reconnect indefinitely
  • PingServer - 1 or 0 - if active will temporaly ping the server to assure the connection is still alive
  • SendAsync - 1 or 0 - if active will send messages assyncronously
  • ParseCommands - add commands to be automatically parsed when a message is received. Commands should be given in a string with the commands prefixes split by a |. For each command add a new option starting with the command prefix and the bang to be executed when the command is received.
    Note: $message$ keyword will be replaced by the content of the command message received
For more information please check the basic example provided with the plugin.

Github: https://github.com/ILikon/WebSocketPlugins
Latest Release: https://github.com/ILikon/WebSocketPlugins/releases/latest

This plugin was developed as part of a personal project. To see it in use check: https://github.com/ILikon/TabletCompanion
Also thread in this forum: https://forum.rainmeter.net/viewtopic.php?f=27&t=29659
RiseUp
Posts: 6
Joined: November 3rd, 2017, 8:08 pm

Re: WebSocket Client Plugin

Post by RiseUp »

Likon wrote: October 13th, 2018, 3:36 pm A plugin for Rainmeter that implements a WebSocket client...
Thank you for posting this, Likon. I am playing around with it at the moment and it's working quite well. :thumbup:
iftl2015
Posts: 4
Joined: July 31st, 2022, 10:42 pm

Re: WebSocket Client Plugin

Post by iftl2015 »

Thank you for making this plugin. I am trying to make it work with a stock price websocket site. It uses the following format:

wss://ws.yuzu.dev/ws?token=YUZU_PUBLIC_TOKEN&streams=S:BBO:AAPL

Using the plugin, I got an error "An exception has ....."

I've also tried using another site:

wss://ws.finnhub.io?token=API_KEY

I got the "Connection Opened" message but I don't know how to pass the "ws.send" to the site. This is the sample code from finnhub (Python):

Code: Select all

#https://pypi.org/project/websocket_client/
import websocket

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("### closed ###")

def on_open(ws):
    ws.send('{"type":"subscribe","symbol":"AAPL"}')
    ws.send('{"type":"subscribe","symbol":"AMZN"}')
    ws.send('{"type":"subscribe","symbol":"BINANCE:BTCUSDT"}')
    ws.send('{"type":"subscribe","symbol":"IC MARKETS:1"}')

if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("wss://ws.finnhub.io?token=",
                              on_message = on_message,
                              on_error = on_error,
                              on_close = on_close)
    ws.on_open = on_open
    ws.run_forever()
My question is does the plugin work with these kinds of sites? If so, how would I send the "on_open" commands?

Thanks
User avatar
tass_co
Posts: 511
Joined: May 4th, 2020, 3:01 pm
Location: Ankara, TURKEY

Re: WebSocket Client Plugin

Post by tass_co »

iftl2015 wrote: July 31st, 2022, 10:51 pm I am trying to make it work with a stock price websocket site.
First of all, If you share a code, use the code section on the panel :thumbup:

You can do this in a simple way with Webparser.
Since I do not know your API key, I am sharing an example for the Binance exchange.
Skin shows 3 Symbols.
You just need to change the TradeSymbol variables to the parity you want.

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=0

;=====================================================================================
[Variables]
TradeSymbol1=BTCUSDT 
TradeSymbol2=ADAUSDT
TradeSymbol3=USDTTRY

TextFace=Product Sans
TextCol=255,255,255
TextSize=15
TextSpacing=15

;---------- PRICE ----------
UpCol=0,255,0           
DownCol=255,120,120

;---------- PERCENTAGE CHANGE ----------
;0=VISIBLE, 1=HIDDEN
PercentageEnabled=0
PercentageTextSize=(#TextSize# * 0.5)

;---------- BINANCE API TRADESYMBOL 1 ----------
[MeasureBinancePriceData1]
Measure=WebParser
URL=https://api.binance.me/api/v3/ticker/24hr?symbol=#TradeSymbol1#
UpdateRate=2
RegExp=(?siU)"priceChangePercent":"(.*)","weightedAvgPrice":".*","prevClosePrice":".*","lastPrice":"(.*)"
OnConnectErrorAction=[!SetOption MeterPrice1 Text "Error obtaining data from binance!"]
UpdateDivider=5

[MeasurePrice1]
Measure=WebParser
URL=[MeasureBinancePriceData1]
StringIndex=2
IfAboveValue=#LastPriceTradeSymbol1#
IfAboveAction=[!SetOption MeterTL4 FontColor #UpCol#][!SetOption MeterPrice1 Text ""][!SetVariable LastPriceTradeSymbol1 [MeasurePrice1]]
IfBelowValue=#LastPriceTradeSymbol1#
IfBelowAction=[!SetOption MeterTL4 FontColor #DownCol#][!SetOption MeterPrice1 Text ""][!SetVariable LastPriceTradeSymbol1 [MeasurePrice1]]
DynamicVariables=1
OnConnectErrorAction=[!SetOption MeterPrice1 Text "Error obtaining data from binance!"]
;Truncation
RegExpSubstitute=1
Substitute="(.*\.\d{2})\d*":"\1"
UpdateDivider=5

;---------- BINANCE API TRADESYMBOL 2 ----------
[MeasureBinancePriceData2]
Measure=WebParser
URL=https://api.binance.com/api/v3/ticker/24hr?symbol=#TradeSymbol2#
UpdateRate=2
RegExp=(?siU)"priceChangePercent":"(.*)","weightedAvgPrice":".*","prevClosePrice":".*","lastPrice":"(.*)"
OnConnectErrorAction=[!SetOption MeterPrice2 Text "Error obtaining data from binance!"]
UpdateDivider=5

[MeasurePrice2]
Measure=WebParser
URL=[MeasureBinancePriceData2]
StringIndex=2
IfAboveValue=#LastPriceTradeSymbol2#
IfAboveAction=[!SetOption MeterTL3 FontColor #UpCol#][!SetOption MeterPrice2 Text ""][!SetVariable LastPriceTradeSymbol2 [MeasurePrice2]]
IfBelowValue=#LastPriceTradeSymbol2#
IfBelowAction=[!SetOption MeterTL3 FontColor #DownCol#][!SetOption MeterPrice2 Text ""][!SetVariable LastPriceTradeSymbol2 [MeasurePrice2]]
DynamicVariables=1
OnConnectErrorAction=[!SetOption MeterPrice2 Text "Error obtaining data from binance!"]
RegExpSubstitute=1
Substitute="(.*\.\d{4})\d*":"\1"
UpdateDivider=5

[MeasureBinancePriceData3]
Measure=WebParser
URL=https://api.binance.com/api/v3/ticker/24hr?symbol=#TradeSymbol3#
UpdateRate=2
RegExp=(?siU)"priceChangePercent":"(.*)","weightedAvgPrice":".*","prevClosePrice":".*","lastPrice":"(.*)"
OnConnectErrorAction=[!SetOption MeterPrice2 Text "Error obtaining data from binance!"]
UpdateDivider=5

[MeasurePrice3]
Measure=WebParser
URL=[MeasureBinancePriceData3]
StringIndex=2
IfAboveValue=#LastPriceTradeSymbol3#
IfAboveAction=[!SetOption MeterTL2 FontColor #UpCol#][!SetOption MeterPrice3 Text ""][!SetVariable LastPriceTradeSymbol3 [MeasurePrice3]]
IfBelowValue=#LastPriceTradeSymbol3#
IfBelowAction=[!SetOption MeterTL2 FontColor #DownCol#][!SetOption MeterPrice3 Text ""][!SetVariable LastPriceTradeSymbol3 [MeasurePrice3]]
DynamicVariables=1
OnConnectErrorAction=[!SetOption MeterPrice3 Text "Error obtaining data from binance!"]
RegExpSubstitute=1
Substitute="(.*\.\d{3})\d*":"\1"
UpdateDivider=5
;================================================

[MeterSymbolLabel1]
Meter=String
Text=BTC
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
FontSize=#TextSize#
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
StringStyle=Bold
StringAlign=Right
X=320
Y=-1

[MeterPrice1]
Meter=String
Text=Getting Price...
MeasureName=MeasurePrice1
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
FontSize=#TextSize#
NumOfDecimals=4
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
StringStyle=Bold
StringAlign=Right
DynamicVariables=1
X=424
Y=-1

;---------- METER 2 ----------

[MeterSymbolLabel2]
DynamicVariables=1
Meter=String
Text=ADA
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
FontSize=#TextSize#
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
StringStyle=Bold
StringAlign=Right
X=328
Y=19

[MeterPrice2]
Meter=String
Text=Getting Price...
MeasureName=MeasurePrice2
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
FontSize=#TextSize#
StringStyle=Bold
StringAlign=Right
NumOfDecimals=4
DynamicVariables=1
X=424
Y=19

[MeterSymbolLabel3]
DynamicVariables=1
Meter=String
Text=USD
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
FontSize=#TextSize#
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
StringStyle=Bold
StringAlign=Right
X=326
Y=39

[MeterPrice3]
Meter=String
Text=Getting Price...
MeasureName=MeasurePrice3
AntiAlias=1
FontFace=Calibri CAPS
FontColor=255,255,255
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
FontSize=#TextSize#
StringStyle=Bold
StringAlign=Right
NumOfDecimals=4
DynamicVariables=1
X=424
Y=39

[MeterTL4]
Meter=STRING
MeasureName=MeasurePrice1
X=438
Y=-1
FontSize=#TextSize#
FontColor=#TextCol#
StringAlign=right
StringStyle=Bold
FontFace=Ubuntu
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
Antialias=1
Text="$"
DynamicVariables=1

[MeterTL3]
Meter=STRING
MeasureName=MeasurePrice2
X=438
Y=20
FontSize=#TextSize#
FontColor=#TextCol#
StringAlign=right
StringStyle=Bold
FontFace=Ubuntu
StringEffect=SHADOW
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
Antialias=1
Text="$"
DynamicVariables=1

[MeterTL2]
Meter=STRING
MeasureName=MeasurePrice3
X=441
Y=46
FontSize=13
FontColor=#TextCol#
StringAlign=right
;StringStyle=Bold
FontFace=Ubuntu
StringEffect=SHADOW
Antialias=1
InlineSetting=Face | IcoFont
InlinePattern=[\xea1e]
InlineSetting=Shadow | 0 | 0 | 1.5 | 0,0,0
Text=[\xea1e]
DynamicVariables=1

I don't know where i going from here, but i promise it won't be boring... :great:
iftl2015
Posts: 4
Joined: July 31st, 2022, 10:42 pm

Re: WebSocket Client Plugin

Post by iftl2015 »

Sorry as that was my first post and didn't put the code in the code section. Will do that in the future :great:

Currently I am using Webparser on CNBC website to get stock info and it is working ok. Here is what I want to have:
1. Premarket & Afterhour price (OTC)
2. Last trade time
3. Volume
4. Bid & Ask (CNBC doesn't have this information but I may be add this in the future if I can figure out Websocket)

The problem with Webparser is the above information is inconsistent and no No.1. Sometimes it is correct and sometimes it is not. I suspect that is because of it has multiple tag "ExtendedMktQuote" and it gives different data.

Also, if CNBC redesign their site, probably a rewrite is needed or if they change to server side code, Webparser will not work. That's why I am hoping to use WebSocket.

Thanks for sharing your code :thumbup:
User avatar
tass_co
Posts: 511
Joined: May 4th, 2020, 3:01 pm
Location: Ankara, TURKEY

Re: WebSocket Client Plugin

Post by tass_co »

iftl2015 wrote: August 1st, 2022, 5:32 am Sorry as that was my first post and didn't put the code in the code section. Will do that in the future :great:

Currently I am using Webparser on CNBC website to get stock info and it is working ok. Here is what I want to have:
1. Premarket & Afterhour price (OTC)
2. Last trade time
3. Volume
4. Bid & Ask (CNBC doesn't have this information but I may be add this in the future if I can figure out Websocket)

The problem with Webparser is the above information is inconsistent and no No.1. Sometimes it is correct and sometimes it is not. I suspect that is because of it has multiple tag "ExtendedMktQuote" and it gives different data.

Also, if CNBC redesign their site, probably a rewrite is needed or if they change to server side code, Webparser will not work. That's why I am hoping to use WebSocket.

Thanks for sharing your code :thumbup:
If you share the page you want to get data from, maybe I can help
I don't know where i going from here, but i promise it won't be boring... :great:
iftl2015
Posts: 4
Joined: July 31st, 2022, 10:42 pm

Re: WebSocket Client Plugin

Post by iftl2015 »

Sure, this code was created by Jacob Allen named MinimalStockTracker. I've modified it to suit my needs. The section is [MesasureYuzuPriceData]. I've tried finnhub.io and got "Connection Opened" but I don't know how to send subscribe message to the WebSocket. Yuzu seems to have better service but I got an error message "An exception has occurred while attempting to connect".

I appreciate you taking a look for me :bow:

Please don't mind the mess as the script has not been cleaned up yet.
You do not have the required permissions to view the files attached to this post.
User avatar
tass_co
Posts: 511
Joined: May 4th, 2020, 3:01 pm
Location: Ankara, TURKEY

Re: WebSocket Client Plugin

Post by tass_co »

iftl2015 wrote: August 4th, 2022, 4:50 am Sure, this code was created by Jacob Allen named MinimalStockTracker. I've modified it to suit my needs. The section is [MesasureYuzuPriceData]. I've tried finnhub.io and got "Connection Opened" but I don't know how to send subscribe message to the WebSocket. Yuzu seems to have better service but I got an error message "An exception has occurred while attempting to connect".

I appreciate you taking a look for me :bow:

Please don't mind the mess as the script has not been cleaned up yet.
I checked the relevant section.
The address of the site from which you want to receive data is unusual. No data is coming!
I searched the site a bit. You can also use the address starting with "wss" as "sse".
wss://ws.yuzu.dev/ws?token=UVUWVktGFGpjK6hw&streams=C:T:BTC-USD => https://sse.yuzu.dev/sse?token=UVUWVktGFGpjK6hw&streams=C:T:BTC-USD
In this way, you can download the data of the market parity you want.
But since this data does not expire, Rainmeter also causes a crash.
If you want to get data from this site , you will need a script (Lua or Python) not WebsocketClient plugin.
I think this way
I don't know where i going from here, but i promise it won't be boring... :great:
iftl2015
Posts: 4
Joined: July 31st, 2022, 10:42 pm

Re: WebSocket Client Plugin

Post by iftl2015 »

Ok, got it! I will look into learning Lua or Python. Thank you again for putting your time into this. Cheers :cheers:
User avatar
tass_co
Posts: 511
Joined: May 4th, 2020, 3:01 pm
Location: Ankara, TURKEY

Re: WebSocket Client Plugin

Post by tass_co »

iftl2015 wrote: August 4th, 2022, 10:42 pm Ok, got it! I will look into learning Lua or Python. Thank you again for putting your time into this. Cheers :cheers:
:thumbup:
I don't know where i going from here, but i promise it won't be boring... :great: