123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- #!/usr/bin/env python3
- from http.server import HTTPServer, BaseHTTPRequestHandler
- from io import BytesIO
- import json
- from subprocess import check_call, check_output
- from multiprocessing import Process
- import os
- import time, arrow
- import requests
- import socket, datetime
- from signal import signal, SIGINT
- import sys
- import humanize
- PATH = os.path.dirname(os.path.realpath(__file__))
- # {'commits': [{'timestamp': '2019-02-22T22:40:15+01:00', 'id': 'b679892b2176a0a23195784f082ee7902709cd10', 'modified': ['README.md'], 'author': {'name': 'Francois Deppierraz', 'username': 'francois', 'email': 'francois@ctrlaltdel.ch'}, 'removed': [], 'added': [], 'url': 'https://git.fixme.ch/francois/screen/commit/b679892b2176a0a23195784f082ee7902709cd10', 'committer': {'name': 'Francois Deppierraz', 'username': 'francois', 'email': 'francois@ctrlaltdel.ch'}, 'message': 'test\n'}], 'before': 'e82e9dc32b5fbe7bf405e4b514de029a87a01e3a', 'pusher': {'id': 19, 'login': 'francois', 'username': 'francois', 'full_name': '', 'avatar_url': 'https://git.fixme.ch/avatars/19', 'email': 'francois@ctrlaltdel.ch'}, 'compare_url': 'https://git.fixme.ch/francois/screen/compare/e82e9dc32b5fbe7bf405e4b514de029a87a01e3a...b679892b2176a0a23195784f082ee7902709cd10', 'ref': 'refs/heads/master', 'sender': {'id': 19, 'login': 'francois', 'username': 'francois', 'full_name': '', 'avatar_url': 'https://git.fixme.ch/avatars/19', 'email': 'francois@ctrlaltdel.ch'}, 'after': 'b679892b2176a0a23195784f082ee7902709cd10', 'repository': {'stars_count': 0, 'size': 110592, 'website': '', 'full_name': 'francois/screen', 'html_url': 'https://git.fixme.ch/francois/screen', 'name': 'screen', 'mirror': False, 'forks_count': 0, 'clone_url': 'https://git.fixme.ch/francois/screen.git', 'open_issues_count': 0, 'description': '', 'updated_at': '2019-02-22T22:39:49+01:00', 'created_at': '2019-02-22T22:23:09+01:00', 'empty': False, 'fork': False, 'watchers_count': 1, 'id': 219, 'default_branch': 'master', 'parent': None, 'private': False, 'ssh_url': 'ssh://gogs@git.fixme.ch:1337/francois/screen.git', 'owner': {'id': 19, 'login': 'francois', 'username': 'francois', 'full_name': '', 'avatar_url': 'https://git.fixme.ch/avatars/19', 'email': 'francois@ctrlaltdel.ch'}}}
- def send_data(uri, data):
- # Limited to 1.5KB
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.sendto(b'%s:%s' % (uri.encode('ascii'), data.encode('utf8')) , ('127.0.0.1', 4444))
- def webhook():
- class WebhookHTTPRequestHandler(BaseHTTPRequestHandler):
- def do_POST(self):
- content_length = int(self.headers['Content-Length'])
- body = self.rfile.read(content_length)
- self.send_response(200)
- self.end_headers()
- data = json.loads(body.decode('utf-8'))
- print(data)
- check_call(('git', 'fetch'))
- check_call(('git', 'reset', '--hard', 'origin/master'))
- httpd = HTTPServer(('0.0.0.0', 8000), WebhookHTTPRequestHandler)
- httpd.serve_forever()
- def calendar():
- import cal
- while True:
- events = cal.get_data()
- filepath = PATH + '/events.json'
- if os.path.getsize(filepath) != len(json.dumps(events)):
- f = open(filepath, 'w+')
- f.write(json.dumps(events))
- f.close()
- time.sleep(3600)
- def power():
- SENSORS = (
- '34cde81adabfb1ce819eca8fea6949b6',
- 'b7755b5f3ec05fcdc67f449241a9912a',
- 'e67e0685f747b30d855108ab781abdfc'
- )
- URL = "http://62.220.135.196:8080/sensor/{}?version=1.0&interval=minute&unit=watt"
- while True:
- power = 0
- for sensor in SENSORS:
- try:
- power += requests.get(URL.format(sensor)).json()[-2][1]
- except:
- print("Failed to read sensor {}".format(sensor))
- send_data('screen/power/set', str(power))
- time.sleep(1)
- def bus():
- limit = 2
- URL = 'https://transport.opendata.ch/v1/stationboard?id=8592223&limit={}&type=departure&transportations[]=bus'.format(limit)
- while True:
- data = requests.get(URL).json()
- times = []
- for i in range(limit):
- _ts = data['stationboard'][i]['stop']['departureTimestamp']
- _time = arrow.get(_ts).humanize()
- times.append(_time)
- f = open(PATH + '/bus.txt', 'w')
- f.write(' and '.join(times))
- f.close()
- time.sleep(30)
- def clock():
- while True:
- now = datetime.datetime.now()
- since_midnight = (
- now -
- now.replace(hour=0, minute=0, second=0)
- ).seconds
- send_data('screen/analogclock/clock/set', str(since_midnight))
- time.sleep(1)
- def random_image():
- #URL='http://aws.random.cat/meow'
- URL='https://picsum.photos/id/10/640/480'
- while True:
- j = requests.get(URL).json()
- response = requests.get(j['file'], stream=True)
- handle = open('./random_image.jpg', "wb")
- for chunk in response.iter_content(chunk_size=512):
- if chunk:
- handle.write(chunk)
- handle.close()
- time.sleep(60)
- # Copied from humanize.naturalsize and s/bytes/bits/g
- def naturalsize(value, binary=False, gnu=False, format='%.1f'):
- """Format a number of byteslike a human readable filesize (eg. 10 kB). By
- default, decimal suffixes (kB, MB) are used. Passing binary=true will use
- binary suffixes (KiB, MiB) are used and the base will be 2**10 instead of
- 10**3. If ``gnu`` is True, the binary argument is ignored and GNU-style
- (ls -sh style) prefixes are used (K, M) with the 2**10 definition.
- Non-gnu modes are compatible with jinja2's ``filesizeformat`` filter."""
- suffixes = {
- 'decimal': ('kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb'),
- 'binary': ('Kib', 'Mib', 'Gib', 'Tib', 'Pib', 'Eib', 'Zib', 'Yib'),
- 'gnu': "KMGTPEZY",
- }
- if gnu: suffix = suffixes['gnu']
- elif binary: suffix = suffixes['binary']
- else: suffix = suffixes['decimal']
- base = 1024 if (gnu or binary) else 1000
- bytes = float(value)
- if bytes == 1 and not gnu: return '1 bit'
- elif bytes < base and not gnu: return '%d bits' % bytes
- elif bytes < base and gnu: return '%db' % bytes
- for i,s in enumerate(suffix):
- unit = base ** (i+2)
- if bytes < unit and not gnu:
- return (format + ' %s') % ((base * bytes / unit), s)
- elif bytes < unit and gnu:
- return (format + '%s') % ((base * bytes / unit), s)
- if gnu:
- return (format + '%s') % ((base * bytes / unit), s)
- return (format + ' %s') % ((base * bytes / unit), s)
- def snmp():
- INTERVAL = 3
- previous_input = 0
- previous_output = 0
- while True:
- result = check_output(('snmpget', '-c', 'uDee4pie', '-v', '2c', '192.168.130.1', '1.3.6.1.2.1.31.1.1.1.6.7', '1.3.6.1.2.1.31.1.1.1.10.7')).decode('ascii').split('\n')
- input = int(result[0].split(' ')[3])
- output = int(result[1].split(' ')[3])
- # print("input=%d, output=%d" % (input, output))
- in_bw = naturalsize(8 * round((input - previous_input) / INTERVAL, 1))
- out_bw = naturalsize(8 * round((output - previous_output) / INTERVAL, 1))
- if previous_input:
- send_data('screen/network/in/set', str(in_bw))
- send_data('screen/network/out/set', str(out_bw))
- previous_input = input
- previous_output = output
- time.sleep(INTERVAL)
- def spaceapi():
- while True:
- data = requests.get('https://fixme.ch/cgi-bin/spaceapi.py').json()
- filepath = PATH + '/spaceapi.json'
- if os.path.getsize(filepath) != len(json.dumps(data)):
- f = open(filepath, 'w+')
- f.write(json.dumps(data))
- f.close()
- time.sleep(10)
- def cleanExit(sig, frame):
- sys.exit(0)
- if __name__ == '__main__':
- signal(SIGINT, cleanExit)
- functions = [
- bus,
- webhook,
- calendar,
- power,
- clock,
- snmp,
- spaceapi,
- random_image,
- ]
- processes = {f: Process(target=f) for f in functions}
- [p.start() for p in processes.values()] # start the processes
- # Control loop
- while True:
- time.sleep(0.5)
- for f,p in processes.items():
- if not p.is_alive():
- processes[f] = Process(target=f)
- processes[f].start()
- print('restarted {}'.format(f))
|