Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ __pycache__
.DS_Store
build
dist
storage

airq/storage
.eggs/
.idea/
AirQ.egg-info/
storage
7 changes: 6 additions & 1 deletion airq/__main__.py
Original file line number Diff line number Diff line change
@@ -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__)
51 changes: 43 additions & 8 deletions airq/app.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down Expand Up @@ -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:
Expand All @@ -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(
Expand All @@ -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(" ", "")
26 changes: 13 additions & 13 deletions airq/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}",
}

Expand Down
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"iconfile": "icon.icns",
"plist": {
"LSUIElement": True,
"CFBundleShortVersionString": "0.1.0",
"CFBundleShortVersionString": "0.2.0",
},
"packages": ["rumps"],
}
Expand All @@ -20,5 +20,5 @@
app=APP,
data_files=DATA_FILES,
options={"py2app": OPTIONS},
setup_requires=["py2app"],
setup_requires=["py2app"]
)