diff --git a/.gitignore b/.gitignore index e630cf3..0674889 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,9 @@ __pycache__ .DS_Store build dist -storage \ No newline at end of file + +airq/storage +.eggs/ +.idea/ +AirQ.egg-info/ +storage diff --git a/airq/__main__.py b/airq/__main__.py index 19865ff..d8ed681 100644 --- a/airq/__main__.py +++ b/airq/__main__.py @@ -1,16 +1,21 @@ -__version__ = "0.1.0" +__version__ = "0.2.0" import os +import logging from dotenv import load_dotenv from airq.app import App from airq.api import Uhoo +logger = logging.getLogger(__name__) + load_dotenv() USERNAME = os.getenv("USERNAME") PASSWORD = os.getenv("PASSWORD") if __name__ == "__main__": + logger.info("Starting AirQ v%s", __version__) app = App(Uhoo(USERNAME, PASSWORD)) app.run() + logger.info("Exiting AirQ v%s", __version__) diff --git a/airq/app.py b/airq/app.py index 079e84c..31e1b36 100644 --- a/airq/app.py +++ b/airq/app.py @@ -1,8 +1,13 @@ import json from datetime import datetime import rumps -from airq import consts +from AppKit import NSAttributedString +from PyObjCTools.Conversion import propertyListFromPythonCollection +from Cocoa import (NSFont, NSFontAttributeName, + NSColor, NSForegroundColorAttributeName) + +from airq import consts class App(rumps.App): def __init__(self, api): @@ -58,7 +63,9 @@ def update_status(self, data): # sensor values values = data[0] formatted_values = {} + warning_values = [] for key, label in consts.LABELS.items(): + warningColor = None if key == consts.KEY_SEPARATOR: continue elif key == consts.KEY_LASTFETCH: @@ -67,20 +74,48 @@ def update_status(self, data): value = datetime.fromtimestamp(values[key]) elif not isinstance(values[key], int): value = values[key]["value"] + warningColor = values[key]["color"] else: value = values[key] - formatted_values[key] = label.format(value) - new_title = ( - consts.WARN_ICON + " " if key in self.warns else "" - ) + formatted_values[key] + + if key == consts.KEY_TEMP: + new_title = label.format(value, (value - 32) / 1.8) + else: + new_title = label.format(value) self.menu[key].title = new_title + formatted_values[key] = new_title + + if warningColor == 'yellow': + color = NSColor.colorWithCalibratedRed_green_blue_alpha_(204/255, 204/255, 0, 1) + font = NSFont.fontWithName_size_("Courier-Bold", 14.0) + warning_values = warning_values + [new_title] + elif warningColor == 'red': + color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, 1) + font = NSFont.fontWithName_size_("Courier-Bold", 14.0) + warning_values = [new_title] + warning_values + else: + color = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 186.0/255, 44.0/255, 1) + font = NSFont.fontWithName_size_("Courier", 14.0) + + attributes = propertyListFromPythonCollection({ + NSFontAttributeName: font, + NSForegroundColorAttributeName: color} + , conversionHelper=lambda x: x) + string = NSAttributedString.alloc().initWithString_attributes_(new_title, attributes) + self.menu[key]._menuitem.setAttributedTitle_(string) + + # use the major changers as the second info + warned_sensor = formatted_values[consts.KEY_DUST].replace(" ", "") + if warning_values: + warned_sensor = warning_values[0].replace(" ", "") title_format = consts.DEFAULT_TITLE_FORMAT self.title = title_format.format( icon=new_icon, - temp=self.strip_sensor_name(formatted_values[consts.KEY_TEMP]), - co2=self.strip_sensor_name(formatted_values[consts.KEY_CO2]) + temp=self.strip_sensor_name(formatted_values[consts.KEY_TEMP].replace(" ", "").split("/")[0]), + hisensor=self.strip_sensor_name(warned_sensor) ) + @rumps.clicked("Debug") def debug(self, sender): rumps.Window( @@ -90,4 +125,4 @@ def debug(self, sender): ).run() def strip_sensor_name(self, formatted_value): - return " ".join(formatted_value.split(" ")[-2:]) + return (" ".join(formatted_value.split(" ")[-2:])).replace(" ", "") diff --git a/airq/consts.py b/airq/consts.py index 5065da3..dec001f 100644 --- a/airq/consts.py +++ b/airq/consts.py @@ -12,21 +12,21 @@ KEY_LASTFETCH = "lastfetch" KEY_SEPARATOR = "separator" -DEFAULT_TITLE_FORMAT = "{icon} {temp} / {co2}" +DEFAULT_TITLE_FORMAT = "{icon} {temp} {hisensor}" LABELS = { - KEY_CO: "CO {} ppm", - KEY_CO2: "CO₂ {} ppm", - KEY_NO2: "NO₂ {} ppb", - KEY_VOC: "TVOC {} ppb", - KEY_DUST: "Dust {} ug/m³", - KEY_TEMP: "Temp {} °C", - KEY_OZONE: "Ozone {} ppb", - KEY_PRESSURE: "Pressure {} hPa", - KEY_HUMIDITY: "Humidity {} %", - KEY_VIRUSSCORE: "Virus Score {}/10", - KEY_SEPARATOR: "--", - KEY_TIMESTAMP: "Measured {:%H:%M:%S}", + KEY_CO: " CO: {} ppm", + KEY_CO2: " CO₂: {} ppm", + KEY_NO2: " NO₂: {} ppb", + KEY_VOC: " TVOC: {} ppb", + KEY_DUST: " Dust: {} ug/m³", + KEY_TEMP: " Temp: {:.1f}°F/{:.1f}°C", + KEY_OZONE: " Ozone: {} ppb", + KEY_PRESSURE: "Pressure: {} hPa", + KEY_HUMIDITY: "Humidity: {}%", + KEY_VIRUSSCORE: " Virus: {}/10", + KEY_SEPARATOR: "--", + KEY_TIMESTAMP: "Measured: {:%H:%M:%S}", KEY_LASTFETCH: "Retrieved {:%H:%M:%S}", } diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..48866f7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +urllib3~=1.26.7 +requests~=2.26.0 +rumps~=0.3.0 +python-dotenv~=0.19.1 +pycryptodome +PyObjC~=7.3 +PyCocoa +logging \ No newline at end of file diff --git a/setup.py b/setup.py index 685a02c..2928875 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ "iconfile": "icon.icns", "plist": { "LSUIElement": True, - "CFBundleShortVersionString": "0.1.0", + "CFBundleShortVersionString": "0.2.0", }, "packages": ["rumps"], } @@ -20,5 +20,5 @@ app=APP, data_files=DATA_FILES, options={"py2app": OPTIONS}, - setup_requires=["py2app"], + setup_requires=["py2app"] )