Source code for pywws.Tasks

#!/usr/bin/env python

# pywws - Python software for USB Wireless Weather Stations
# http://github.com/jim-easterbrook/pywws
# Copyright (C) 2008-13  Jim Easterbrook  jim@jim-easterbrook.me.uk

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

"""Routines to perform common tasks such as plotting gaphs or uploading files."""

from datetime import datetime, timedelta
import logging
import os
import shutil

from pywws.calib import Calib
from pywws import Plot
from pywws import Template
from pywws.TimeZone import Local
from pywws.toservice import ToService
from pywws import Upload
from pywws import WindRose
from pywws import YoWindow

[docs]class RegularTasks(object): def __init__(self, params, status, calib_data, hourly_data, daily_data, monthly_data): self.logger = logging.getLogger('pywws.Tasks.RegularTasks') self.params = params self.status = status self.calib_data = calib_data self.hourly_data = hourly_data self.daily_data = daily_data self.monthly_data = monthly_data # get directories self.work_dir = self.params.get('paths', 'work', '/tmp/weather') self.template_dir = self.params.get( 'paths', 'templates', os.path.expanduser('~/weather/templates/')) self.graph_template_dir = self.params.get( 'paths', 'graph_templates', os.path.expanduser('~/weather/graph_templates/')) self.local_dir = self.params.get( 'paths', 'local_files', os.path.expanduser('~/weather/results/')) # create calibration object self.calibrator = Calib(self.params, self.status) # create templater object self.templater = Template.Template( self.params, self.status, self.calib_data, self.hourly_data, self.daily_data, self.monthly_data) # create plotter objects self.plotter = Plot.GraphPlotter( self.params, self.status, self.calib_data, self.hourly_data, self.daily_data, self.monthly_data, self.work_dir) self.roseplotter = WindRose.RosePlotter( self.params, self.status, self.calib_data, self.hourly_data, self.daily_data, self.monthly_data, self.work_dir) # directory of service uploaders self.services = dict() # create a YoWindow object self.yowindow = YoWindow.YoWindow(self.calib_data) # get local time's offset from UTC, without DST now = self.calib_data.before(datetime.max) if not now: now = datetime.utcnow() time_offset = Local.utcoffset(now) - Local.dst(now) # get daytime end hour, in UTC self.day_end_hour = eval(params.get('config', 'day end hour', '21')) self.day_end_hour = (self.day_end_hour - (time_offset.seconds // 3600)) % 24 # create service uploader objects for section in ('live', 'logged', 'hourly', '12 hourly', 'daily'): for service in eval(self.params.get(section, 'services', '[]')): if service not in self.services: self.services[service] = ToService( self.params, self.status, self.calib_data, service_name=service)
[docs] def has_live_tasks(self): yowindow_file = self.params.get('live', 'yowindow', '') if yowindow_file: return True for template in eval(self.params.get('live', 'twitter', '[]')): return True for service in eval(self.params.get('live', 'services', '[]')): return True for template in eval(self.params.get('live', 'plot', '[]')): return True for template in eval(self.params.get('live', 'text', '[]')): return True return False
def _parse_templates(self, section, option): for template in eval(self.params.get(section, option, '[]')): if isinstance(template, (list, tuple)): yield template else: yield template, ''
[docs] def do_live(self, data): data = self.calibrator.calib(data) OK = True yowindow_file = self.params.get('live', 'yowindow', '') if yowindow_file: self.yowindow.write_file(yowindow_file, data) for template, flags in self._parse_templates('live', 'twitter'): if not self.do_twitter(template, data): OK = False for service in eval(self.params.get('live', 'services', '[]')): self.services[service].Upload(data) uploads = [] local_files = [] for template, flags in self._parse_templates('live', 'plot'): upload = self.do_plot(template) if not upload: continue if 'L' in flags: local_files.append(upload) else: uploads.append(upload) for template, flags in self._parse_templates('live', 'text'): if 'T' in flags: if not self.do_twitter(template, data): OK = False continue upload = self.do_template(template, data) if 'L' in flags: local_files.append(upload) else: uploads.append(upload) if local_files: if not os.path.isdir(self.local_dir): os.makedirs(self.local_dir) for file in local_files: shutil.move(file, self.local_dir) if uploads: if not Upload.Upload(self.params, uploads): OK = False for file in uploads: os.unlink(file) return OK
[docs] def do_tasks(self): sections = ['logged'] self.params.unset('logged', 'last update') now = self.calib_data.before(datetime.max) if now: now += timedelta(minutes=self.calib_data[now]['delay']) else: now = datetime.utcnow() threshold = now.replace(minute=0, second=0, microsecond=0) last_update = self.params.get_datetime('hourly', 'last update') if last_update: self.params.unset('hourly', 'last update') self.status.set('last update', 'hourly', last_update.isoformat(' ')) last_update = self.status.get_datetime('last update', 'hourly') if (not last_update) or (last_update < threshold): # time to do hourly tasks sections.append('hourly') # set 12 hourly threshold threshold -= timedelta(hours=(threshold.hour - self.day_end_hour) % 12) last_update = self.params.get_datetime('12 hourly', 'last update') if last_update: self.params.unset('12 hourly', 'last update') self.status.set('last update', '12 hourly', last_update.isoformat(' ')) last_update = self.status.get_datetime('last update', '12 hourly') if (not last_update) or (last_update < threshold): # time to do 12 hourly tasks sections.append('12 hourly') # set daily threshold threshold -= timedelta(hours=(threshold.hour - self.day_end_hour) % 24) last_update = self.params.get_datetime('daily', 'last update') if last_update: self.params.unset('daily', 'last update') self.status.set('last update', 'daily', last_update.isoformat(' ')) last_update = self.status.get_datetime('last update', 'daily') if (not last_update) or (last_update < threshold): # time to do daily tasks sections.append('daily') OK = True for section in sections: for template, flags in self._parse_templates(section, 'twitter'): if not self.do_twitter(template): OK = False for section in sections: yowindow_file = self.params.get(section, 'yowindow', '') if yowindow_file: self.yowindow.write_file(yowindow_file) break all_services = list() for section in sections: for service in eval(self.params.get(section, 'services', '[]')): if service not in all_services: all_services.append(service) for service in all_services: self.services[service].Upload(True) uploads = [] local_files = [] for section in sections: for template, flags in self._parse_templates(section, 'plot'): upload = self.do_plot(template) if not upload: continue if 'L' in flags: local_files.append(upload) else: uploads.append(upload) for template, flags in self._parse_templates(section, 'text'): if 'T' in flags: if not self.do_twitter(template): OK = False continue upload = self.do_template(template) if 'L' in flags: local_files.append(upload) else: uploads.append(upload) if local_files: if not os.path.isdir(self.local_dir): os.makedirs(self.local_dir) for file in local_files: shutil.move(file, self.local_dir) if uploads: if not Upload.Upload(self.params, uploads): OK = False for file in uploads: os.unlink(file) if OK: for section in sections: self.status.set('last update', section, now.isoformat(' ')) if 'hourly' in sections: # save any unsaved data self.params.flush() self.status.flush() self.calib_data.flush() self.hourly_data.flush() self.daily_data.flush() self.monthly_data.flush() return OK
[docs] def do_twitter(self, template, data=None): from pywws import ToTwitter twitter = ToTwitter.ToTwitter(self.params) self.logger.info("Templating %s", template) input_file = os.path.join(self.template_dir, template) tweet = self.templater.make_text(input_file, live_data=data) self.logger.info("Tweeting") return twitter.Upload(tweet[:140])
[docs] def do_plot(self, template): self.logger.info("Graphing %s", template) input_file = os.path.join(self.graph_template_dir, template) output_file = os.path.join(self.work_dir, os.path.splitext(template)[0]) if self.plotter.DoPlot(input_file, output_file) == 0: return output_file elif self.roseplotter.DoPlot(input_file, output_file) == 0: return output_file return None
[docs] def do_template(self, template, data=None): self.logger.info("Templating %s", template) input_file = os.path.join(self.template_dir, template) output_file = os.path.join(self.work_dir, template) self.templater.make_file(input_file, output_file, live_data=data) return output_file