{"id":415,"date":"2025-08-19T18:38:56","date_gmt":"2025-08-19T13:08:56","guid":{"rendered":"http:\/\/byomkesh.in\/wordpress\/?page_id=415"},"modified":"2025-08-19T19:16:57","modified_gmt":"2025-08-19T13:46:57","slug":"systray-using-python","status":"publish","type":"page","link":"http:\/\/byomkesh.in\/wordpress\/systray-using-python\/","title":{"rendered":"SysTray using Python"},"content":{"rendered":"<p>create an alerts.txt file with following:<\/p>\n<p>25000, above<br \/>\n24900, below<\/p>\n<p>Then create a python script\u00a0 nifty_tray.py :<\/p>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/p>\n<pre>import time\r\nimport threading\r\nimport requests\r\n\"\"\"from win10toast import ToastNotifier\"\"\"\r\nimport pystray\r\nfrom PIL import Image, ImageDraw\r\nimport os\r\nimport queue\r\nfrom winotify import Notification, audio\r\n\r\nCHECK_INTERVAL = 30\r\nALERTS_FILE = os.path.join(os.path.dirname(__file__), \"alerts.txt\")\r\n\r\ncurrent_ltp = 0\r\nicon = None\r\nalerts = []\r\n\"\"\"toaster = ToastNotifier()\"\"\"\r\nalert_state = {}\r\nnotif_queue = queue.Queue()\r\n\r\n\r\ndef load_alerts():\r\n    \"\"\"Load alerts from alerts.txt\"\"\"\r\n    global alerts, alert_state\r\n    alerts = []\r\n    if not os.path.exists(ALERTS_FILE):\r\n        return\r\n    with open(ALERTS_FILE, \"r\") as f:\r\n        for line in f:\r\n            line = line.strip()\r\n            if not line or line.startswith(\"#\"):\r\n                continue\r\n            try:\r\n                level_str, direction = line.split(\",\")\r\n                level = float(level_str.strip())\r\n                direction = direction.strip().lower()\r\n                alerts.append((level, direction))\r\n                if (level, direction) not in alert_state:\r\n                    alert_state[(level, direction)] = False\r\n            except Exception:\r\n                continue\r\n\r\n\r\ndef fetch_nifty():\r\n    \"\"\"Fetch latest Nifty value\"\"\"\r\n    url = \"https:\/\/www.nseindia.com\/api\/marketStatus\"\r\n    headers = {\r\n        \"User-Agent\": \"Mozilla\/5.0\",\r\n        \"Accept\": \"application\/json\",\r\n        \"Referer\": \"https:\/\/www.nseindia.com\/\"\r\n    }\r\n    try:\r\n        resp = requests.get(url, headers=headers, timeout=10)\r\n        data = resp.json()\r\n        return float(data[\"marketState\"][0][\"last\"])\r\n    except Exception:\r\n        return 0\r\n\r\n\r\ndef queue_notification(title, message):\r\n    notif_queue.put((title, message))\r\n\r\n\r\ndef process_notifications():\r\n    while not notif_queue.empty():\r\n        title, message = notif_queue.get_nowait()\r\n        toast = Notification(app_id=\"Nifty Tray\",\r\n                             title=title,\r\n                             msg=message,\r\n                             duration=\"short\")\r\n        toast.set_audio(audio.Default, loop=False)\r\n        toast.show()\r\n\r\n\r\ndef monitor_price():\r\n    \"\"\"Monitor Nifty price and trigger alerts\"\"\"\r\n    global current_ltp, icon\r\n    while True:\r\n        load_alerts()\r\n        ltp = fetch_nifty()\r\n        if ltp > 0:\r\n            current_ltp = ltp\r\n            if icon:\r\n                icon.title = f\"Nifty: {ltp}\"\r\n\r\n            for level, direction in alerts:\r\n                key = (level, direction)\r\n                if direction == \"above\":\r\n                    if ltp > level and not alert_state[key]:\r\n                        queue_notification(\"Nifty Alert\", f\"Nifty crossed above {level} (Now {ltp})\")\r\n                        alert_state[key] = True\r\n                    elif ltp <= level:\r\n                        alert_state[key] = False\r\n                elif direction == \"below\":\r\n                    if ltp < level and not alert_state[key]:\r\n                        queue_notification(\"Nifty Alert\", f\"Nifty crossed below {level} (Now {ltp})\")\r\n                        alert_state[key] = True\r\n                    elif ltp >= level:\r\n                        alert_state[key] = False\r\n\r\n        time.sleep(CHECK_INTERVAL)\r\n\r\n\r\ndef notification_loop():\r\n    \"\"\"Background loop to process notifications\"\"\"\r\n    while True:\r\n        process_notifications()\r\n        time.sleep(1)\r\n\r\n\r\ndef create_image():\r\n    \"\"\"Tray icon image\"\"\"\r\n    img = Image.new(\"RGB\", (64, 64), \"green\")\r\n    d = ImageDraw.Draw(img)\r\n    d.rectangle([16, 16, 48, 48], fill=\"white\")\r\n    return img\r\n\r\n\r\ndef quit_app(icon_obj, item):\r\n    icon_obj.stop()\r\n\r\n\r\ndef run_tray():\r\n    global icon\r\n    load_alerts()\r\n    icon = pystray.Icon(\r\n        \"nifty\",\r\n        create_image(),\r\n        \"Nifty: Loading...\",\r\n        menu=pystray.Menu(pystray.MenuItem(\"Quit\", quit_app))\r\n    )\r\n\r\n    # background threads\r\n    threading.Thread(target=monitor_price, daemon=True).start()\r\n    threading.Thread(target=notification_loop, daemon=True).start()\r\n\r\n    # run tray icon loop\r\n    icon.run()\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    run_tray()\r\n<\/pre>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\ninstall following python modules<\/p>\n<p>pip install requests plyer pystray pillow<br \/>\npip install pyinstaller<br \/>\npip install win10toast<br \/>\npip install winotify<br \/>\npip install &#8211;upgrade packaging<\/p>\n<p>Now Compile the above script to generate an exe file:<\/p>\n<pre>C:\\Users\\admin\\AppData\\Roaming\\Python\\Python312\\Scripts\\pyinstaller.exe --noconsole --onefile nifty_tray.py<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>create an alerts.txt file with following: 25000, above 24900, below Then create a python script\u00a0 nifty_tray.py : &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; import time import threading import requests &#8220;&#8221;&#8221;from win10toast import ToastNotifier&#8221;&#8221;&#8221; import pystray from PIL import Image, ImageDraw import os import queue from winotify import Notification, audio CHECK_INTERVAL = 30 ALERTS_FILE = os.path.join(os.path.dirname(__file__), &#8220;alerts.txt&#8221;) current_ltp = 0 icon &hellip; <a href=\"http:\/\/byomkesh.in\/wordpress\/systray-using-python\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">SysTray using Python<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-415","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/pages\/415","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/comments?post=415"}],"version-history":[{"count":4,"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/pages\/415\/revisions"}],"predecessor-version":[{"id":421,"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/pages\/415\/revisions\/421"}],"wp:attachment":[{"href":"http:\/\/byomkesh.in\/wordpress\/wp-json\/wp\/v2\/media?parent=415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}