Skip to content

Instantly share code, notes, and snippets.

@tommie
Created November 13, 2020 22:33
Show Gist options
  • Save tommie/ea2d1160bf0d7f6cdb0abfb45d12e26f to your computer and use it in GitHub Desktop.
Save tommie/ea2d1160bf0d7f6cdb0abfb45d12e26f to your computer and use it in GitHub Desktop.
i3wttr
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import json
import logging
import signal
import socket
import sys
import threading
import time
import urllib.parse
import urllib.request
class WttrClient(object):
UPDATE_INTERVAL = 3600
URL = 'https://wttr.in/'
LINE_FORMAT = '1'
def __init__(self):
self._weather_data = {}
self._running = True
self._lock = threading.Lock()
self._cond = threading.Condition(self._lock)
self._thread = threading.Thread(target=self._run, name='WeatherUpdater')
self._thread.start()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def get_local_weather(self):
with self._lock:
return self._weather_data.get('local', None)
def close(self):
with self._lock:
self._running = False
self._cond.notify_all()
self._thread.join()
@property
def _is_running(self):
return self._running and self._thread.is_alive()
def _run(self):
try:
while self._is_running:
try:
logging.debug('Entering read loop...')
with urllib.request.urlopen(self.URL + '?' + urllib.parse.urlencode({'format': self.LINE_FORMAT})) as f:
line = f.read().decode('utf-8').strip()
with self._lock:
self._weather_data['local'] = line
delay = self.UPDATE_INTERVAL
except Exception as ex:
logging.warning('Request failed: %s', ex)
delay = self.UPDATE_INTERVAL * 0.1
with self._lock:
while self._is_running:
if self._cond.wait(delay):
break
except BaseException as ex:
logging.exception('Receive thread failed: %s', ex)
raise
def get_weather(client):
line = client.get_local_weather()
if not line: return []
return [{
'full_text': client.get_local_weather(),
'name': 'wttr',
'markup': 'none',
'instance': 'local',
}]
if __name__ == '__main__':
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
# websocket-client causes SIGPIPE.
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
with WttrClient() as wttr:
# Skip the first line which contains the version header.
print(sys.stdin.readline().strip(), flush=True)
# The second line contains the start of the infinite array.
print(sys.stdin.readline().strip(), flush=True)
for line in sys.stdin:
line = line.strip()
prefix = ''
# ignore comma at start of lines
if line.startswith(','):
line, prefix = line[1:], ','
j = json.loads(line)
try:
j = list(get_weather(wttr)) + j
except BaseException as ex:
logging.exception('Failed to generate content (ignored): %s',
ex)
print(prefix + json.dumps(j), flush=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment