52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
import time
|
|
import urllib.request
|
|
|
|
from .config import Config
|
|
from .events import error_event, status_event
|
|
from .http import HttpFailure, request_json
|
|
from .smartthings import SmartThingsClient, TokenManager
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class Poller:
|
|
def __init__(self, config: Config):
|
|
self.config = config
|
|
tokens = TokenManager(config.client_id, config.client_secret, config.refresh_token,
|
|
config.access_token, config.token_file, config.request_timeout_seconds)
|
|
self.client = SmartThingsClient(config.api_base_url, config.device_id, tokens, config.request_timeout_seconds)
|
|
|
|
def poll_once(self) -> dict:
|
|
try:
|
|
event = status_event(self.config, self.client.get_status())
|
|
except Exception as error:
|
|
event = error_event(self.config, error)
|
|
self.publish(event)
|
|
return event
|
|
|
|
def publish(self, event: dict) -> None:
|
|
data = json.dumps(event, ensure_ascii=False, separators=(",", ":")).encode()
|
|
request = urllib.request.Request(self.config.redpanda_url, data=data, method="POST",
|
|
headers={"Content-Type": "application/json", "Accept": "application/json"})
|
|
try:
|
|
request_json(request, self.config.redpanda_timeout_seconds)
|
|
except HttpFailure:
|
|
LOG.exception("Could not publish event to Redpanda Connect")
|
|
raise
|
|
|
|
def run(self) -> None:
|
|
while True:
|
|
started = time.monotonic()
|
|
try:
|
|
event = self.poll_once()
|
|
LOG.log(logging.WARNING if event["level"] != "info" else logging.INFO,
|
|
"Poll result: %s", event["status"])
|
|
except Exception:
|
|
LOG.exception("Poll cycle failed")
|
|
time.sleep(max(0, self.config.interval_seconds - (time.monotonic() - started)))
|
|
|