My morning report is a text file printed every morning on my dot-matrix printer. It contains:
This is done by 3 supporting Python scripts, a shell script to put them all together, and a cron job to automate it.
The cron job merely runs the shell script daily at 07:45 and redirects the output to the printer:
45 7 * * * ~/projects/morning-report/morning-report.sh > /dev/usb/lp0 2> ~/projects/log/error.txt
Note that stderr is redirected to an error logging file, for debugging purposes.
This script puts the results of all the other scripts together in a format that is nice for my printer to print, outputting it to stdout.
#!/bin/bashIt first sources the Python3 virtual environment for this project on my raspberry pi, then it outputs a command that makes the printer switch the font size, then it runs log-report.py and weather-report.py, column-stacks and outputs them, and finally runs news-report.py and outputs it.
cd ~/projects/morning-report
. bin/activate
echo -ne "\x1B\x67" #switch to 15cpi
python3 log-report.py > log-report
python3 weather-report.py > weather-report
paste log-report weather-report | column -s $'\t' -tn
python3 news-report.py > news-report
cat news-report
Source: morning-report.sh
log-report.py is a Python script which downloads my productivity data, makes some calculations and outputs it, and also downloads my calendar, interprets it, and outputs some useful information.
from pyexcel_ods import get_data
import numpy as np
import pandas as pd
from datetime import datetime, date
from pytz import timezone
from icalendar import Calendar, Event
import requests
import recurring_ical_events
import calendar
current=datetime.now(timezone('UTC'))
print(str(current.date())+", "+calendar.day_name[current.weekday()]+"\n")
2021-03-08, Monday
r=requests.get("[log url]")
with open("logv2.ods","wb") as f:
f.write(r.content)
spread=get_data("logv2.ods")
data=spread['Sheet1']
columns=["D","WD","startutc","startlocal","activity","detail","people","super","spent","","subplace","place","city","country","spentint"]
df=pd.DataFrame(data,columns=columns)
df.drop([0],inplace=True)
df.drop([""],axis=1,inplace=True)
df.reset_index(inplace=True,drop=True)
df.drop(df.tail(2).index, inplace = True) #drop last 2 rows
df['activity'].replace('', np.nan, inplace=True)
df.dropna(subset=['activity'], inplace=True)
def get_n(threshold):
length=len(df["startutc"])
n=min(threshold*120,length-2)
delta=df["startutc"][length-1]-df["startutc"][length-n]
days=delta.total_seconds()/3600/24
while(days>=threshold):
n-=1
delta=df["startutc"][length-1]-df["startutc"][length-n]
days=delta.total_seconds()/3600/24
return n
labels=["productive","fun","routine","waste"]
filters=[{LIST OF PRODUCTIVE STRINGS},
{LIST OF FUN STRINGS},
{LIST OF ROUTINE STRINGS},
{LIST OF WASTE STRINGS}]
def get_times(n):
i=n
total=0
times=np.zeros(4)
total=0
length=len(df["startutc"])
for i in range(2,n+1):
activity=df["activity"][length-i]
time=df["spentint"][length-i]
if activity != "sleep":
total+=time
for j in range (0, len(labels)):
if activity in filters[j]:
times[j]+=time
times=times/total
times=[round(t,3) for t in times]
# for i in range(0,len(times)):
# times[i]=round(times[i],3)
return times
def output_times(days, timess):
df=pd.DataFrame(timess.T,columns=days,index=labels)
df.columns.name='past days'
print(df)
def print_times(dayss):
timess=[]
for days in dayss:
timess.append(get_times(get_n(days)))
output_times(dayss,np.array(timess))
print_times([1,7,30,365,df['D'].iloc[-1]])
past days 1 7 30 365 1027
productive 0.163 0.044 0.181 0.229 0.206
fun 0.552 0.596 0.396 0.298 0.180
routine 0.072 0.082 0.072 0.068 0.069
waste 0.058 0.101 0.080 0.111 0.089
r=requests.get("[webDAV calendar URL]")
with open("cal.ics","wb") as f:
f.write(r.content)
cal=Calendar.from_ical(open("cal.ics","rb").read())
recurring = recurring_ical_events.of(cal).at(date.today())
def eventcompare(e):
return e["DTSTART"].dt
recurring.sort(key=eventcompare)
print("\nCALENDAR")
for component in recurring:
start=component["DTSTART"].dt.time()
end=component["DTEND"].dt.time()
print(str(start)+"-"+str(end)+" "+component["SUMMARY"])
CALENDAR
08:10:00-10:00:00 cc
19:10:00-20:25:00 linreg
print("\nTODO")
def todocompare(e):
return e["DUE"].dt
eventsort=[e for e in cal.walk() if e.name=="VTODO" and e["STATUS"]!="COMPLETED"]
eventsort.sort(key=todocompare)
for component in eventsort:
if component.name=="VTODO" and component["STATUS"]!="COMPLETED":
#print(component)
dt=component["DUE"].dt
print(str(dt.date())+" "+str(dt.time())+" "+component["SUMMARY"])
TODO
2021-03-08 14:00:00 groceries
2021-03-10 08:00:00 fundies-hw5
2021-03-13 23:59:00 bayesian-hw4
Source: log-report.py
weather-report.py is a Python script which makes a request to the OpenWeatherMap API and outputs some useful weather information.
#!/usr/bin/env python
import requests
import numpy as np
import pandas as pd
from datetime import datetime, date
r=requests.get('https://api.openweathermap.org/data/2.5/onecall?lat=LATITUDE&lon=LONGITUDE&exclude=minutely,daily&appid=APIKEY')
data=r.json()
sunrise=str(datetime.fromtimestamp(data["current"]["sunrise"]).time())
sunset=str(datetime.fromtimestamp(data["current"]["sunset"]).time())
print("sunrise:"+sunrise+" sunset:"+sunset)
sunrise:06:18:30 sunset:17:54:39
hourly=np.array(data['hourly'])[:24]
times=[datetime.fromtimestamp(hour["dt"]).time() for hour in hourly]
temps=[round(hour["temp"]-273.15) for hour in hourly]
feels_likes=[round(hour["feels_like"]-273.15) for hour in hourly]
descs=[hour["weather"][0]['description'] for hour in hourly]
weather=pd.DataFrame(list(zip(times,temps,feels_likes,descs)),columns=["Time","Temp","Feels","Description"])
print(weather.to_string(index=False)+"\n")
Time Temp Feels Description
13:00:00 3 -2 clear sky
14:00:00 3 -2 clear sky
15:00:00 4 -1 clear sky
16:00:00 4 0 clear sky
17:00:00 5 1 clear sky
18:00:00 4 1 clear sky
19:00:00 4 0 clear sky
20:00:00 3 -1 clear sky
21:00:00 3 -1 scattered clouds
22:00:00 3 -1 scattered clouds
23:00:00 3 -2 few clouds
00:00:00 3 -2 scattered clouds
01:00:00 3 -2 scattered clouds
02:00:00 3 -2 scattered clouds
03:00:00 3 -3 broken clouds
04:00:00 3 -2 broken clouds
05:00:00 4 -2 broken clouds
06:00:00 4 -2 overcast clouds
07:00:00 4 -1 broken clouds
08:00:00 5 0 clear sky
09:00:00 7 2 clear sky
10:00:00 9 4 clear sky
11:00:00 10 4 clear sky
12:00:00 10 5 clear sky
Source: weather-report.py
news-report.py is a Python script which uses RSS to grab some news headlines and upcoming rocket launches.
#!/usr/bin/env python
# coding: utf-8
import feedparser
from datetime import datetime, date
from time import mktime
import requests
import numpy as np
urls=["rss feed url 1","rss feed url 2"…]
feeds=[]
for url in urls:
feeds.append(feedparser.parse(url))
now=datetime.now()
for d in feeds:
entries=[]
for entry in d['entries']:
ts=entry['published_parsed']
#print(ts)
delta=now-datetime.fromtimestamp(mktime(ts))
days=delta.total_seconds()/60/60/24
if(days<1):
entries.append(entry['title'])
if entries:
print(d['feed']['title']+"---------------------------")
for entry in entries:
print(entry)
print("rockets:-----------------")
r=requests.get('https://fdo.rocketlaunch.live/json/launches/next/5')
data=np.array(r.json()['result'])[:2]
for launch in data:
date=str(datetime.fromtimestamp(int(launch['sort_date'])))
provider=launch['provider']['name']
vehicle=launch['vehicle']['name']
mission=launch['missions'][0]['name']
print(date+": "+provider+" "+vehicle+". "+launch['missions'][0]['name'])
print("\x1BJ\xD8\x1BJ\xD8\x1BJ\x6C")
Note that, at the very end, it also outputs some bytes which tell the printer to feed the paper out a few centimeters.
Source: news-report.py