def calculate_balances(self): from scheduler import predicted_schedule now = datetime.datetime.now() for station in stations.get(): station.balance = { key: value for key, value in station.balance.iteritems() if key >= now.date() - datetime.timedelta(days=21) } if not station.balance or (now.date() - datetime.timedelta(days=21) ) not in station.balance: station.balance[now.date() - datetime.timedelta(days=21)] = { 'eto': 0.0, 'rain': 0.0, 'intervals': [], 'total': 0.0, 'valid': True } runs = log.finished_runs() + log.active_runs() calc_day = now.date() - datetime.timedelta(days=20) while calc_day < now.date() + datetime.timedelta(days=10): if calc_day not in station.balance: station.balance[calc_day] = { 'eto': 4.0, 'rain': 0.0, 'intervals': [], 'total': 0.0, 'valid': False } try: if not station.balance[calc_day][ 'valid'] or calc_day >= now.date(): station.balance[calc_day]['eto'] = weather.get_eto( calc_day) station.balance[calc_day]['rain'] = weather.get_rain( calc_day) station.balance[calc_day]['valid'] = True except Exception: station.balance[calc_day]['valid'] = False logging.warning( 'Could not get weather information, using fallbacks:\n' + traceback.format_exc()) intervals = [] while runs and runs[0]['start'].date() <= calc_day: run = runs[0] if runs[0]['start'].date() == calc_day and not run[ 'blocked'] and run['station'] == station.index: irrigation = (run['end'] - run['start']).total_seconds( ) / 3600 * station.precipitation if run['manual']: irrigation *= 0.5 # Only count half in case of manual runs intervals.append({ 'program': run['program'], 'program_name': run['program_name'], 'done': True, 'irrigation': irrigation }) del runs[0] if calc_day >= now.date(): if calc_day == now.date(): date_time_start = now else: date_time_start = datetime.datetime.combine( calc_day, datetime.time.min) date_time_end = datetime.datetime.combine( calc_day, datetime.time.max) for run in predicted_schedule(date_time_start, date_time_end): if not run['blocked'] and run[ 'station'] == station.index: irrigation = ( run['end'] - run['start'] ).total_seconds() / 3600 * station.precipitation intervals.append({ 'program': run['program'], 'program_name': run['program_name'], 'done': False, 'irrigation': irrigation }) if len(intervals) > len(station.balance[calc_day]['intervals'] ) or calc_day >= now.date(): station.balance[calc_day]['intervals'] = intervals station.balance[calc_day]['total'] = station.balance[calc_day - datetime.timedelta(days=1)]['total'] \ - station.balance[calc_day]['eto'] \ + station.balance[calc_day]['rain'] \ + sum(interval['irrigation'] for interval in station.balance[calc_day]['intervals']) station.balance[calc_day]['total'] = max( -100, min(station.balance[calc_day]['total'], station.capacity)) calc_day += datetime.timedelta(days=1) station.balance = station.balance # Force saving
def run(self): weather.add_callback(self.update) self._sleep(10) # Wait for weather callback before starting while not self._stop_event.is_set(): try: log.clear(NAME) if plugin_options['enabled']: log.debug(NAME, _(u'Checking weather status') + '...') info = [] days = 0 total_info = {'rain_mm': 0.0} for day in range(-plugin_options['days_history'], plugin_options['days_forecast'] + 1): check_date = datetime.date.today( ) + datetime.timedelta(days=day) hourly_data = weather.get_hourly_data(check_date) if hourly_data: days += 1 info += hourly_data total_info['rain_mm'] += weather.get_rain(check_date) log.info( NAME, _(u'Using') + ' %d ' % days + _(u'days of information.')) total_info.update({ 'temp_c': sum([val['temperature'] for val in info]) / len(info), 'wind_ms': sum([val['windSpeed'] for val in info]) / len(info), 'humidity': sum([val['humidity'] for val in info]) / len(info) }) # We assume that the default 100% provides 4mm water per day (normal need) # We calculate what we will need to provide using the mean data of X days around today water_needed = 4 * days # 4mm per day water_needed *= 1 + (total_info['temp_c'] - 20) / 15 # 5 => 0%, 35 => 200% water_needed *= 1 + (total_info['wind_ms'] / 100 ) # 0 => 100%, 20 => 120% water_needed *= 1 - (total_info['humidity'] - 50) / 200 # 0 => 125%, 100 => 75% water_needed = round(water_needed, 1) water_left = water_needed - total_info['rain_mm'] water_left = round(max(0, min(100, water_left)), 1) water_adjustment = round((water_left / (4 * days)) * 100, 1) water_adjustment = float( max(plugin_options['wl_min'], min(plugin_options['wl_max'], water_adjustment))) log.info( NAME, _(u'Water needed') + ' %d ' % days + _('days') + ': %.1fmm' % water_needed) log.info( NAME, _(u'Total rainfall') + ': %.1fmm' % total_info['rain_mm']) log.info(NAME, u'_______________________________') log.info(NAME, _(u'Irrigation needed') + ': %.1fmm' % water_left) log.info( NAME, _(u'Weather Adjustment') + ': %.1f%%' % water_adjustment) level_adjustments[NAME] = water_adjustment / 100 if plugin_options['protect_enabled']: current_data = weather.get_current_data() temp_local_unit = current_data[ 'temperature'] if options.temp_unit == "C" else 32.0 + 9.0 / 5.0 * current_data[ 'temperature'] log.debug( NAME, _(u'Temperature') + ': %.1f %s' % (temp_local_unit, options.temp_unit)) month = time.localtime().tm_mon # Current month. if temp_local_unit < plugin_options[ 'protect_temp'] and month in plugin_options[ 'protect_months']: station_seconds = {} for station in stations.enabled_stations(): if station.index in plugin_options[ 'protect_stations']: station_seconds[ station.index] = plugin_options[ 'protect_minutes'] * 60 else: station_seconds[station.index] = 0 for station in stations.enabled_stations(): if run_once.is_active(datetime.datetime.now(), station.index): break else: log.debug(NAME, _(u'Protection activated.')) run_once.set(station_seconds) self._sleep(3600) else: log.clear(NAME) log.info(NAME, _(u'Plug-in is disabled.')) if NAME in level_adjustments: del level_adjustments[NAME] self._sleep(24 * 3600) except Exception: log.error( NAME, _(u'Weather-based water level plug-in') + ':\n' + traceback.format_exc()) self._sleep(3600) weather.remove_callback(self.update)
def calculate_balances(self): from scheduler import predicted_schedule now = datetime.datetime.now() for station in stations.get(): station.balance = {key: value for key, value in station.balance.iteritems() if key >= now.date() - datetime.timedelta(days=21)} if not station.balance or (now.date() - datetime.timedelta(days=21)) not in station.balance: station.balance[now.date() - datetime.timedelta(days=21)] = { 'eto': 0.0, 'rain': 0.0, 'intervals': [], 'total': 0.0, 'valid': True } runs = log.finished_runs() + log.active_runs() calc_day = now.date() - datetime.timedelta(days=20) while calc_day < now.date() + datetime.timedelta(days=7): if calc_day not in station.balance: station.balance[calc_day] = { 'eto': 4.0, 'rain': 0.0, 'intervals': [], 'total': 0.0, 'valid': False } try: if not station.balance[calc_day]['valid'] or calc_day >= now.date() - datetime.timedelta(days=1): station.balance[calc_day]['eto'] = station.eto_factor * weather.get_eto(calc_day) station.balance[calc_day]['rain'] = 0.0 if station.ignore_rain else weather.get_rain(calc_day) station.balance[calc_day]['valid'] = True except Exception: station.balance[calc_day]['valid'] = False logging.warning('Could not get weather information, using fallbacks:\n' + traceback.format_exc()) intervals = [] while runs and runs[0]['start'].date() <= calc_day: run = runs[0] if runs[0]['start'].date() == calc_day and not run['blocked'] and run['station'] == station.index: irrigation = (run['end'] - run['start']).total_seconds() / 3600 * station.precipitation if run['manual']: irrigation *= 0.5 # Only count half in case of manual runs intervals.append({ 'program': run['program'], 'program_name': run['program_name'], 'done': True, 'irrigation': irrigation }) del runs[0] if calc_day >= now.date(): if calc_day == now.date(): date_time_start = now else: date_time_start = datetime.datetime.combine(calc_day, datetime.time.min) date_time_end = datetime.datetime.combine(calc_day, datetime.time.max) for run in predicted_schedule(date_time_start, date_time_end): if not run['blocked'] and run['station'] == station.index: irrigation = (run['end'] - run['start']).total_seconds() / 3600 * station.precipitation intervals.append({ 'program': run['program'], 'program_name': run['program_name'], 'done': False, 'irrigation': irrigation }) if len(intervals) > len(station.balance[calc_day]['intervals']) or calc_day >= now.date(): station.balance[calc_day]['intervals'] = intervals station.balance[calc_day]['total'] = station.balance[calc_day - datetime.timedelta(days=1)]['total'] \ - station.balance[calc_day]['eto'] \ + station.balance[calc_day]['rain'] \ + sum(interval['irrigation'] for interval in station.balance[calc_day]['intervals']) station.balance[calc_day]['total'] = max(-100, min(station.balance[calc_day]['total'], station.capacity)) calc_day += datetime.timedelta(days=1) station.balance = station.balance # Force saving
def run(self): weather.add_callback(self.update) self._sleep(10) # Wait for weather callback before starting while not self._stop_event.is_set(): try: log.clear(NAME) if plugin_options['enabled']: log.debug(NAME, _(u'Checking weather status') + '...') if plugin_options['use_netatmo']: authorization = ClientAuth() devList = WeatherStationData(authorization) now = time.time() begin = now - ( plugin_options['days_history']) * 24 * 3600 mac2 = plugin_options['netatmomac'] rainmac2 = plugin_options['netatmorain'] resp = (devList.getMeasure(mac2, '1hour', 'sum_rain', rainmac2, date_begin=begin, date_end=now, limit=None, optimize=False)) result = [(time.ctime(int(k)), v[0]) for k, v in resp['body'].items()] result.sort() xdate, xrain = zip(*result) zrain = 0 for yrain in xrain: zrain = zrain + yrain else: zrain = 0 info = [] days = 0 total_info = {'rain_mm': 0.0} for day in range(-plugin_options['days_history'], plugin_options['days_forecast'] + 1): check_date = datetime.date.today( ) + datetime.timedelta(days=day) hourly_data = weather.get_hourly_data(check_date) if hourly_data: days += 1 info += hourly_data total_info['rain_mm'] += weather.get_rain(check_date) log.info( NAME, _(u'Using') + ' %d ' % days + _(u'days of information.')) total_info.update({ 'temp_c': sum([val['temperature'] for val in info]) / len(info), 'wind_ms': sum([val['windSpeed'] for val in info]) / len(info), 'humidity': sum([val['humidity'] for val in info]) / len(info) }) # We assume that the default 100% provides 4mm water per day (normal need) # We calculate what we will need to provide using the mean data of X days around today water_needed = 4 * days # 4mm per day water_needed *= 1 + (total_info['temp_c'] - 20) / 15 # 5 => 0%, 35 => 200% water_needed *= 1 + (total_info['wind_ms'] / 100 ) # 0 => 100%, 20 => 120% water_needed *= 1 - (total_info['humidity'] - 50) / 200 # 0 => 125%, 100 => 75% water_needed = round(water_needed, 1) water_left = water_needed - total_info['rain_mm'] water_left = round(max(0, min(100, water_left)), 1) water_adjustment = round((water_left / (4 * days)) * 100, 1) level_adjustments[NAME] = water_adjustment / 100 if plugin_options['use_netatmo']: water_left = water_needed - zrain - total_info[ 'rain_mm'] water_left = round(max(0, min(100, water_left)), 1) else: water_left = water_needed - total_info['rain_mm'] water_left = round(max(0, min(100, water_left)), 1) water_adjustment = round( (water_left / ((plugin_options['netatmo_level']) * days)) * 100, 1) water_adjustment = float( max(plugin_options['wl_min'], min(plugin_options['wl_max'], water_adjustment))) log.info( NAME, _(u'Water needed') + '(%d ' % days + _(u'days') + '): %.1fmm' % water_needed) log.info( NAME, _(u'Total rainfall') + ': %.1fmm' % total_info['rain_mm']) log.info(NAME, _(u'_______________________________')) log.info(NAME, _(u'Irrigation needed') + ': %.1fmm' % water_left) log.info( NAME, _(u'Weather Adjustment') + ': %.1f%%' % water_adjustment) log.info(NAME, _(u'_______________________________')) log.info( NAME, _(u'History rain by Netatmo') + ': %.1fmm' % zrain) self._sleep(3600) else: log.clear(NAME) log.info(NAME, _(u'Plug-in is disabled.')) if NAME in level_adjustments: del level_adjustments[NAME] self._sleep(24 * 3600) except Exception: log.error( NAME, _(u'Weather-based water level plug-in') + ':\n' + traceback.format_exc()) self._sleep(3600) weather.remove_callback(self.update)