1
0
mirror of https://github.com/no2chem/wideq.git synced 2025-05-31 22:40:15 -07:00

Add logging

Instead of using print, let's use Python's logging framework. That
allows switching verbosity easily and filtering out unwanted messages.
Some of the setup code is inspired by what Home Assistant does.
This commit is contained in:
Frederik Gladhorn 2020-01-22 14:50:32 +01:00 committed by Frederik Gladhorn
parent be05e1b33e
commit 919139d9e8
4 changed files with 75 additions and 16 deletions

View File

@ -6,9 +6,12 @@ import time
import argparse import argparse
import sys import sys
import re import re
import os.path
import logging
from typing import List from typing import List
STATE_FILE = 'wideq_state.json' STATE_FILE = 'wideq_state.json'
LOGGER = logging.getLogger("wideq.example")
def authenticate(gateway): def authenticate(gateway):
@ -166,20 +169,26 @@ EXAMPLE_COMMANDS = {
def example_command(client, cmd, args): def example_command(client, cmd, args):
func = EXAMPLE_COMMANDS.get(cmd) func = EXAMPLE_COMMANDS.get(cmd)
if not func: if not func:
print("Invalid command: '{}'.\n" LOGGER.error("Invalid command: '%s'.\n"
"Use one of: {}".format(cmd, ', '.join(EXAMPLE_COMMANDS)), "Use one of: %s", cmd, ', '.join(EXAMPLE_COMMANDS))
file=sys.stderr)
return return
func(client, *args) func(client, *args)
def example(country: str, language: str, cmd: str, args: List[str]) -> None: def example(country: str, language: str, verbose: bool,
cmd: str, args: List[str]) -> None:
if verbose:
wideq.set_log_level(logging.DEBUG)
# Load the current state for the example. # Load the current state for the example.
try: try:
with open(STATE_FILE) as f: with open(STATE_FILE) as f:
LOGGER.debug("State file found '%s'", os.path.abspath(STATE_FILE))
state = json.load(f) state = json.load(f)
except IOError: except IOError:
state = {} state = {}
LOGGER.debug("No state file found (tried: '%s')",
os.path.abspath(STATE_FILE))
client = wideq.Client.load(state) client = wideq.Client.load(state)
if country: if country:
@ -198,17 +207,18 @@ def example(country: str, language: str, cmd: str, args: List[str]) -> None:
break break
except wideq.NotLoggedInError: except wideq.NotLoggedInError:
print('Session expired.') LOGGER.info('Session expired.')
client.refresh() client.refresh()
except UserError as exc: except UserError as exc:
print(exc.msg, file=sys.stderr) LOGGER.error(exc.msg)
sys.exit(1) sys.exit(1)
# Save the updated state. # Save the updated state.
state = client.dump() state = client.dump()
with open(STATE_FILE, 'w') as f: with open(STATE_FILE, 'w') as f:
json.dump(state, f) json.dump(state, f)
LOGGER.debug("Wrote state file '%s'", os.path.abspath(STATE_FILE))
def main() -> None: def main() -> None:
@ -232,21 +242,27 @@ def main() -> None:
help=f'language code for the API (default: {wideq.DEFAULT_LANGUAGE})', help=f'language code for the API (default: {wideq.DEFAULT_LANGUAGE})',
default=wideq.DEFAULT_LANGUAGE default=wideq.DEFAULT_LANGUAGE
) )
parser.add_argument(
'--verbose', '-v',
help='verbose mode to help debugging',
action='store_true', default=False
)
args = parser.parse_args() args = parser.parse_args()
country_regex = re.compile(r"^[A-Z]{2,3}$") country_regex = re.compile(r"^[A-Z]{2,3}$")
if not country_regex.match(args.country): if not country_regex.match(args.country):
print("Error: Country must be two or three letters" LOGGER.error("Country must be two or three letters"
f" all upper case (e.g. US, NO, KR) got: '{args.country}'", " all upper case (e.g. US, NO, KR) got: '%s'",
file=sys.stderr) args.country)
exit(1) exit(1)
language_regex = re.compile(r"^[a-z]{2,3}-[A-Z]{2,3}$") language_regex = re.compile(r"^[a-z]{2,3}-[A-Z]{2,3}$")
if not language_regex.match(args.language): if not language_regex.match(args.language):
print("Error: Language must be a combination of language" LOGGER.error("Language must be a combination of language"
" and country (e.g. en-US, no-NO, kr-KR)" " and country (e.g. en-US, no-NO, kr-KR)"
f" got: '{args.language}'", " got: '%s'",
file=sys.stderr) args.language)
exit(1) exit(1)
example(args.country, args.language, args.cmd, args.args) example(args.country, args.language, args.verbose, args.cmd, args.args)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -63,7 +63,7 @@ class DryerStatusTest(unittest.TestCase):
self.assertEqual(TempControl.MID_HIGH, status.temperature_control) self.assertEqual(TempControl.MID_HIGH, status.temperature_control)
self.assertEqual(TimeDry.OFF, status.time_dry) self.assertEqual(TimeDry.OFF, status.time_dry)
@mock.patch('wideq.client.logging') @mock.patch('wideq.client.LOGGER')
def test_properties_unknown_enum_value(self, mock_logging): def test_properties_unknown_enum_value(self, mock_logging):
""" """
This should not raise an error for an invalid enum value and instead This should not raise an error for an invalid enum value and instead

View File

@ -13,6 +13,7 @@ from . import core
#: Represents an unknown enum value. #: Represents an unknown enum value.
_UNKNOWN = 'Unknown' _UNKNOWN = 'Unknown'
LOGGER = logging.getLogger("wideq.client")
class Monitor(object): class Monitor(object):
@ -348,7 +349,7 @@ class ModelInfo(object):
""" """
options = self.value(key).options options = self.value(key).options
if value not in options: if value not in options:
logging.warning( LOGGER.warning(
'Value `%s` for key `%s` not in options: %s. Values from API: ' 'Value `%s` for key `%s` not in options: %s. Values from API: '
'%s', value, key, options, self.data['Value'][key]['option']) '%s', value, key, options, self.data['Value'][key]['option'])
return _UNKNOWN return _UNKNOWN

View File

@ -7,6 +7,7 @@ import hashlib
import hmac import hmac
import datetime import datetime
import requests import requests
import logging
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
GATEWAY_URL = 'https://kic.lgthinq.com:46030/api/common/gatewayUriList' GATEWAY_URL = 'https://kic.lgthinq.com:46030/api/common/gatewayUriList'
@ -22,6 +23,47 @@ DEFAULT_COUNTRY = 'US'
DEFAULT_LANGUAGE = 'en-US' DEFAULT_LANGUAGE = 'en-US'
def get_wideq_logger() -> logging.Logger:
level = logging.INFO
fmt = "%(asctime)s %(levelname)s [%(name)s] %(message)s"
datefmt = "%Y-%m-%d %H:%M:%S"
logger = logging.getLogger("wideq")
logger.setLevel(level)
try:
import colorlog # type: ignore
colorfmt = f"%(log_color)s{fmt}%(reset)s"
handler = colorlog.StreamHandler()
handler.setFormatter(
colorlog.ColoredFormatter(
colorfmt,
datefmt=datefmt,
reset=True,
log_colors={
"DEBUG": "cyan",
"INFO": "green",
"WARNING": "yellow",
"ERROR": "red",
"CRITICAL": "red",
},
)
)
except ImportError:
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(fmt=fmt, datefmt=datefmt))
logger.addHandler(handler)
return logger
LOGGER = get_wideq_logger()
def set_log_level(level: int):
logger = get_wideq_logger()
logger.setLevel(level)
def gen_uuid() -> str: def gen_uuid() -> str:
return str(uuid.uuid4()) return str(uuid.uuid4())