def _check_schedule(): current_time = datetime.datetime.now() check_start = current_time - datetime.timedelta(days=1) check_end = current_time + datetime.timedelta(days=1) rain = not options.manual_mode and (rain_blocks.block_end() > datetime.datetime.now() or inputs.rain_sensed()) active = log.active_runs() for entry in active: ignore_rain = stations.get(entry['station']).ignore_rain if entry['end'] <= current_time or (rain and not ignore_rain and not entry['blocked'] and not entry['manual']): log.finish_run(entry) if not entry['blocked']: stations.deactivate(entry['station']) if not options.manual_mode: schedule = predicted_schedule(check_start, check_end) #import pprint #logging.debug("Schedule: %s", pprint.pformat(schedule)) for entry in schedule: if entry['start'] <= current_time < entry['end']: log.start_run(entry) if not entry['blocked']: stations.activate(entry['station']) if stations.master is not None or options.master_relay: master_on = False # It's easy if we don't have to use delays: if options.master_on_delay == options.master_off_delay == 0: for entry in active: if not entry['blocked'] and stations.get(entry['station']).activate_master: master_on = True break else: # In manual mode we cannot predict, we only know what is currently running and the history if options.manual_mode: active = log.finished_runs() + active else: active = combined_schedule(check_start, check_end) for entry in active: if not entry['blocked'] and stations.get(entry['station']).activate_master: if entry['start'] + datetime.timedelta(seconds=options.master_on_delay) \ <= current_time < \ entry['end'] + datetime.timedelta(seconds=options.master_off_delay): master_on = True break if stations.master is not None: master_station = stations.get(stations.master) if master_on != master_station.active: master_station.active = master_on if options.master_relay: if master_on != outputs.relay_output: outputs.relay_output = master_on
def run(self): log.clear(NAME) log.info(NAME, datetime_string() + ' ' + _(u'Started for {} seconds.').format(plugin_options['open_time'])) start = datetime.datetime.now() sid = int(plugin_options['open_output']) end = datetime.datetime.now() + datetime.timedelta(seconds=plugin_options['open_time']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _(u'Door Opening'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station'])
def run(self): log.clear(NAME) if not plugin_options['enabled']: log.info(NAME, _('Pressurizer is disabled.')) else: log.info(NAME, _('Pressurizer is enabled.')) start_master = False # for master station ON/OFF pressurizer_master_relay_off.send( ) # send signal relay off from this plugin while not self._stop_event.is_set(): try: if plugin_options['enabled']: # plugin is enabled current_time = datetime.datetime.now() user_pre_time = current_time + datetime.timedelta( seconds=int(plugin_options['pre_time'])) check_start = current_time - datetime.timedelta(days=1) check_end = current_time + datetime.timedelta(days=1) schedule = predicted_schedule(check_start, check_end) rain = not options.manual_mode and ( rain_blocks.block_end() > datetime.datetime.now() or inputs.rain_sensed()) if stations.master is None: start_master = False log.clear(NAME) log.info( NAME, datetime_string() + ' ' + _('This plugin requires setting master station to enabled. Setup this in options! And also enable the relay as master station in options!' )) self._sleep(10) for entry in schedule: if entry['start'] <= user_pre_time < entry[ 'end']: # is possible program in this interval? if not rain and not entry[ 'blocked']: # is not blocked and not ignored rain? if stations.master is not None: log.clear(NAME) log.info( NAME, datetime_string() + ' ' + _('Is time for pump running...')) start_master = True if start_master: # is time for run relay pname = _('Pressurizer plug-in') program_name = "%s " % pname.encode( "utf-8", errors="ignore").decode( "utf-8") # program name sname = 0 for station in stations.get(): if station.is_master: sname = station.index # master pump index pend = current_time + datetime.timedelta( seconds=int(plugin_options['run_time'])) _entry = { 'active': None, 'program': -1, 'program_name': program_name, 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': datetime.datetime.now(), 'original_start': datetime.datetime.now(), 'end': pend, 'uid': '%s-%s-%d' % (datetime.datetime.now(), str(program_name), sname), 'usage': 2.0, 'station': sname } if plugin_options['relay']: pressurizer_master_relay_on.send( ) # send signal relay on from this plugin self._sleep(0.5) outputs.relay_output = True # activate relay log.info(NAME, _('Activating relay.')) log.start_run(_entry) wait_for_run = plugin_options[ 'run_time'] # pump run time if wait_for_run > plugin_options[ 'pre_time']: # is not run time > pre run time? wait_for_run = plugin_options[ 'pre_time'] # scheduller tick is 1 second log.info( NAME, datetime_string() + ' ' + _('Waiting') + ' ' + str(wait_for_run) + ' ' + _('second.')) self._sleep( int(wait_for_run)) # waiting on run time pressurizer_master_relay_off.send( ) # send signal relay off from this plugin self._sleep(0.5) outputs.relay_output = False # deactivate relay log.info(NAME, _('Deactivating relay.')) log.finish_run(_entry) log.info(NAME, datetime_string() + ' ' + _('Ready.')) start_master = False seconds = int( plugin_options['mm'] or 0) * 60 + int( plugin_options['ss'] or 0) # (mm:ss) log.info( NAME, datetime_string() + ' ' + _('Waiting') + ' ' + str(seconds) + ' ' + _('second.')) self._sleep( seconds ) # How long after the relay is activated wait for another stations else: self._sleep(2) else: self._sleep(5) self._sleep(1) except Exception: log.error( NAME, _('Pressurizer plug-in') + ':\n' + traceback.format_exc()) self._sleep(60)
def run(self): temperature_ds = [-127, -127, -127, -127, -127, -127] msg_a_on = True msg_a_off = True last_text = '' send = False temp_sw = None if plugin_options['use_footer']: temp_sw = showInFooter( ) # instantiate class to enable data in footer temp_sw.button = "pool_heating/settings" # button redirect on footer temp_sw.label = _('Pool Heating') # label on footer ds_a_on = -127.0 ds_a_off = -127.0 millis = 0 # timer for clearing status on the web pages after 5 sec last_millis = int(round(time.time() * 1000)) safety_start = datetime.datetime.now() safety_end = datetime.datetime.now() + datetime.timedelta( minutes=plugin_options['safety_mm']) a_state = -3 # for state in footer "Waiting." regulation_text = _(u'Waiting to turned on or off.') if not plugin_options['enabled_a']: a_state = -1 # for state in footer "Waiting (not enabled regulation in options)." log.info(NAME, datetime_string() + ' ' + _('Waiting.')) end = datetime.datetime.now() while not self._stop_event.is_set(): try: if plugin_options[ "sensor_probe"] == 2: # loading probe name from plugin air_temp_humi try: from plugins.air_temp_humi import plugin_options as air_temp_data self.status['ds_name_0'] = air_temp_data['label_ds0'] self.status['ds_name_1'] = air_temp_data['label_ds1'] self.status['ds_name_2'] = air_temp_data['label_ds2'] self.status['ds_name_3'] = air_temp_data['label_ds3'] self.status['ds_name_4'] = air_temp_data['label_ds4'] self.status['ds_name_5'] = air_temp_data['label_ds5'] self.status['ds_count'] = air_temp_data['ds_used'] from plugins.air_temp_humi import DS18B20_read_probe # value with temperature from probe DS1-DS6 temperature_ds = [ DS18B20_read_probe(0), DS18B20_read_probe(1), DS18B20_read_probe(2), DS18B20_read_probe(3), DS18B20_read_probe(4), DS18B20_read_probe(5) ] except: log.error( NAME, _('Unable to load settings from Air Temperature and Humidity Monitor plugin! Is the plugin Air Temperature and Humidity Monitor installed and set up?' )) pass # regulation if plugin_options['enabled_a'] and plugin_options[ "sensor_probe"] != 0: # enabled regulation and selected input for probes sensor/airtemp plugin if plugin_options["sensor_probe"] == 1 and sensors.count( ) > 0: sensor_on = sensors.get( int(plugin_options['probe_A_on_sens'])) # pool if sensor_on.sens_type == 5: # temperature sensor ds_a_on = self._try_read(sensor_on.last_read_value) elif sensor_on.sens_type == 6 and sensor_on.multi_type == 0: # multitemperature sensor DS1 ds_a_on = self._try_read( sensor_on.last_read_value[0]) elif sensor_on.sens_type == 6 and sensor_on.multi_type == 1: # multitemperature sensor DS2 ds_a_on = self._try_read( sensor_on.last_read_value[1]) elif sensor_on.sens_type == 6 and sensor_on.multi_type == 2: # multitemperature sensor DS3 ds_a_on = self._try_read( sensor_on.last_read_value[2]) elif sensor_on.sens_type == 6 and sensor_on.multi_type == 3: # multitemperature sensor DS4 ds_a_on = self._try_read( sensor_on.last_read_value[3]) else: ds_a_on = -127.0 sensor_off = sensors.get( int(plugin_options['probe_A_off_sens'])) # solar if sensor_off.sens_type == 5: # temperature sensor ds_a_off = self._try_read( sensor_off.last_read_value) elif sensor_off.sens_type == 6 and sensor_off.multi_type == 0: # multitemperature sensor DS1 ds_a_off = self._try_read( sensor_off.last_read_value[0]) elif sensor_off.sens_type == 6 and sensor_off.multi_type == 1: # multitemperature sensor DS2 ds_a_off = self._try_read( sensor_off.last_read_value[1]) elif sensor_off.sens_type == 6 and sensor_off.multi_type == 2: # multitemperature sensor DS3 ds_a_off = self._try_read( sensor_off.last_read_value[2]) elif sensor_off.sens_type == 6 and sensor_off.multi_type == 3: # multitemperature sensor DS4 ds_a_off = self._try_read( sensor_off.last_read_value[3]) else: ds_a_off = -127.0 elif plugin_options["sensor_probe"] == 2: ds_a_on = temperature_ds[ plugin_options['probe_A_on']] # pool ds_a_off = temperature_ds[ plugin_options['probe_A_off']] # solar station_a = stations.get( plugin_options['control_output_A']) # only for testing... without airtemp plugin or sensors #ds_a_on = 15 #ds_a_off = 25 probes_ok = True if ds_a_on == -127.0 or ds_a_off == -127.0: probes_ok = False a_state = -2 # The station switches off if the sensors has a fault sid = station_a.index active = log.active_runs() for interval in active: if interval['station'] == sid: stations.deactivate(sid) log.finish_run(interval) regulation_text = datetime_string() + ' ' + _( 'Regulation set OFF.') + ' ' + ' (' + _( 'Output') + ' ' + str(station_a.index + 1) + ').' log.clear(NAME) log.info(NAME, regulation_text) # release msg_a_on and msg_a_off to true for future regulation (after probes is ok) msg_a_on = True msg_a_off = True if (ds_a_off - ds_a_on ) > plugin_options['temp_a_on'] and probes_ok: # ON a_state = 1 if msg_a_on: msg_a_on = False msg_a_off = True regulation_text = datetime_string() + ' ' + _( 'Regulation set ON.') + ' ' + ' (' + _( 'Output') + ' ' + str(station_a.index + 1) + ').' log.clear(NAME) log.info(NAME, regulation_text) start = datetime.datetime.now() sid = station_a.index end = datetime.datetime.now() + datetime.timedelta( seconds=plugin_options['reg_ss'], minutes=plugin_options['reg_mm']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _(u'Pool Heating'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if plugin_options[ 'enabled_safety']: # safety check safety_end = datetime.datetime.now( ) + datetime.timedelta( minutes=plugin_options['safety_mm']) if (ds_a_off - ds_a_on ) < plugin_options['temp_a_off'] and probes_ok: # OFF a_state = 0 if msg_a_off: msg_a_off = False msg_a_on = True regulation_text = datetime_string() + ' ' + _( 'Regulation set OFF.') + ' ' + ' (' + _( 'Output') + ' ' + str(station_a.index + 1) + ').' log.clear(NAME) log.info(NAME, regulation_text) sid = station_a.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) if plugin_options[ 'enabled_safety']: # safety check safety_end = datetime.datetime.now( ) + datetime.timedelta( minutes=plugin_options['safety_mm']) ### if "pool" end in schedule release msg_a_on to true in regulation for next scheduling ### now = datetime.datetime.now() if now > end: msg_a_off = False msg_a_on = True if probes_ok: a_state = -3 if plugin_options['enabled_safety']: # safety check safety_start = datetime.datetime.now() if safety_start > safety_end and probes_ok: # is time for check if (ds_a_off - ds_a_on) > plugin_options[ 'temp_safety']: # temperature difference is bigger a_state = -4 msg_a_off = False msg_a_on = True regulation_text = datetime_string() + ' ' + _( 'Safety shutdown!' ) + ' ' + ' (' + _('Output') + ' ' + str( station_a.index + 1) + ').\n' + _('Regulation disabled!') log.clear(NAME) log.info(NAME, regulation_text) sid = station_a.index stations.deactivate(sid) active = log.active_runs() for interval in active: # stop stations if interval['station'] == sid: log.finish_run(interval) send = True # send e-mail plugin_options[ 'enabled_a'] = False # disabling plugin else: if a_state != -4: # if safety error not print waiting also safety shutdown! a_state = -1 # footer text tempText = ' ' if a_state == 0: tempText += regulation_text if a_state == 1: tempText += regulation_text if a_state == -1: tempText = _( 'Waiting (not enabled regulation in options, or not selected input).' ) if a_state == -2: tempText = _( 'Some probe shows a fault, regulation is blocked!') if a_state == -3: tempText = _('Waiting.') if a_state == -4: tempText = _('Safety shutdown!') if plugin_options['use_footer']: if temp_sw is not None: temp_sw.val = tempText.encode('utf8').decode( 'utf8') # value on footer self._sleep(2) millis = int(round(time.time() * 1000)) if (millis - last_millis ) > 5000: # 5 second to clearing status on the webpage last_millis = millis log.clear(NAME) if plugin_options["sensor_probe"] == 1: try: if options.temp_unit == 'C': log.info( NAME, datetime_string() + '\n' + sensor_on.name + ' (' + _('Pool') + ') %.1f \u2103 \n' % ds_a_on + sensor_off.name + ' (' + _('Solar') + ') %.1f \u2103' % ds_a_off) else: log.info( NAME, datetime_string() + '\n' + sensor_on.name + ' (' + _('Pool') + ') %.1f \u2109 \n' % ds_a_on + sensor_off.name + ' (' + _('Solar') + ') %.1f \u2103' % ds_a_off) except: pass elif plugin_options["sensor_probe"] == 2: log.info( NAME, datetime_string() + '\n' + _('Pool') + u' %.1f \u2103 \n' % ds_a_on + _('Solar') + ' %.1f \u2103' % ds_a_off) if last_text != tempText: log.info(NAME, tempText) last_text = tempText if send: msg = '<b>' + _( 'Pool Heating plug-in' ) + '</b> ' + '<br><p style="color:red;">' + _( 'System detected error: The temperature did not drop when the pump was switched on after the setuped time. Stations set to OFF. Safety shutdown!' ) + '</p>' msglog = _( 'System detected error: The temperature did not drop when the pump was switched on after the setuped time. Stations set to OFF. Safety shutdown!' ) send = False try: try_mail = None if plugin_options['eplug'] == 0: # email_notifications from plugins.email_notifications import try_mail if plugin_options[ 'eplug'] == 1: # email_notifications SSL from plugins.email_notifications_ssl import try_mail if try_mail is not None: try_mail( msg, msglog, attachment=None, subject=plugin_options['emlsubject'] ) # try_mail(text, logtext, attachment=None, subject=None) except Exception: log.error( NAME, _('Pool Heating plug-in') + ':\n' + traceback.format_exc()) self._sleep(2) except Exception: log.error( NAME, _('Pool Heating plug-in') + ':\n' + traceback.format_exc()) self._sleep(60)
def run(self): last_millis = 0 # timer for save log once_text = True # once_text to mini is auxiliary for blocking two_text = True three_text = True five_text = True six_text = True send = False mini = True sonic_cm = -1 level_in_tank = 0 regulation_text = _(u'Regulation NONE.') if NAME in rain_blocks: del rain_blocks[NAME] self._sleep(2) tank_mon = None if tank_options['use_footer']: tank_mon = showInFooter( ) # instantiate class to enable data in footer tank_mon.button = "tank_monitor/settings" # button redirect on footer tank_mon.label = _(u'Tank') # label on footer end = datetime.datetime.now() avg_lst = [0] * tank_options['avg_samples'] avg_cnt = 0 avg_rdy = False while not self._stop_event.is_set(): try: if tank_options['use_sonic']: if two_text: log.clear(NAME) log.info(NAME, _(u'Water tank monitor is enabled.')) once_text = True two_text = False ping_read = get_sonic_cm() if tank_options[ 'use_avg'] and ping_read > 0: # use averaging try: avg_lst[avg_cnt] = ping_read except: avg_lst.append(ping_read) avg_cnt += 1 if avg_cnt > tank_options['avg_samples']: avg_cnt = 0 avg_rdy = True if avg_rdy: sonic_cm = average_list(avg_lst) level_in_tank = get_sonic_tank_cm(sonic_cm) else: sonic_cm = 0 log.clear(NAME) log.info( NAME, _(u'Waiting for {} samples to be read from the sensor (when using averaging).' ).format(tank_options['avg_samples'])) else: # without averaging if ping_read > 0: # if sonic value is bad (-1) not use these sonic_cm = ping_read level_in_tank = get_sonic_tank_cm(sonic_cm) else: sonic_cm = 0 level_in_tank = 0 tempText = "" if level_in_tank > 0 and sonic_cm != 0: # if level is ok and sonic is ok three_text = True status['level'] = level_in_tank status['ping'] = sonic_cm status['volume'] = get_volume(level_in_tank) status['percent'] = get_tank(level_in_tank) log.clear(NAME) log.info( NAME, datetime_string() + ' ' + _(u'Water level') + ': ' + str(status['level']) + ' ' + _(u'cm') + ' (' + str(status['percent']) + ' ' + (u'%).')) if tank_options['check_liters']: # display in liters tempText = str( status['volume'] ) + ' ' + _(u'liters') + ', ' + str( status['level']) + ' ' + _(u'cm') + ' (' + str( status['percent']) + ' ' + (u'%)') log.info( NAME, _(u'Ping') + ': ' + str(status['ping']) + ' ' + _(u'cm') + ', ' + _(u'Volume') + ': ' + str(status['volume']) + ' ' + _(u'liters') + '.') else: tempText = str( status['volume'] ) + ' ' + _(u'm3') + ', ' + str( status['level']) + ' ' + _(u'cm') + ' (' + str( status['percent']) + ' ' + (u'%)') log.info( NAME, _(u'Ping') + ': ' + str(status['ping']) + ' ' + _(u'cm') + ', ' + _(u'Volume') + ': ' + str(status['volume']) + ' ' + _(u'm3') + '.') log.info( NAME, str(status['maxlevel_datetime']) + ' ' + _(u'Maximum Water level') + ': ' + str(status['maxlevel']) + ' ' + _(u'cm') + '.') log.info( NAME, str(status['minlevel_datetime']) + ' ' + _(u'Minimum Water level') + ': ' + str(status['minlevel']) + ' ' + _(u'cm') + '.') log.info(NAME, regulation_text) if tank_options[ 'enable_reg']: # if enable regulation "maximum water level" reg_station = stations.get( tank_options['reg_output']) if level_in_tank > tank_options[ 'reg_max']: # if actual level in tank > set maximum water level if five_text: five_text = False six_text = True regulation_text = datetime_string( ) + ' ' + _( u'Regulation set ON.' ) + ' ' + ' (' + _(u'Output') + ' ' + str( reg_station.index + 1) + ').' start = datetime.datetime.now() sid = reg_station.index end = datetime.datetime.now( ) + datetime.timedelta( seconds=tank_options['reg_ss'], minutes=tank_options['reg_mm']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _('Tank Monitor'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if level_in_tank < tank_options[ 'reg_min']: # if actual level in tank < set minimum water level if six_text: # blocking for once five_text = True six_text = False regulation_text = datetime_string( ) + ' ' + _( u'Regulation set OFF.' ) + ' ' + ' (' + _(u'Output') + ' ' + str( reg_station.index + 1) + ').' sid = reg_station.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) now = datetime.datetime.now() if now > end: # if program end in schedule release five_text to true in regulation for next scheduling # five_text = True six_text = False regulation_text = datetime_string() + ' ' + _( u'Waiting.') if status['level'] > status[ 'maxlevel']: # maximum level check status['maxlevel'] = status['level'] tank_options.__setitem__('saved_max', status['level']) status['maxlevel_datetime'] = datetime_string() log.info( NAME, datetime_string() + ': ' + _(u'Maximum has updated.')) update_log() if status['level'] < status['minlevel'] and status[ 'level'] > 2: # minimum level check status['minlevel'] = status['level'] tank_options.__setitem__('saved_min', status['level']) status['minlevel_datetime'] = datetime_string() log.info( NAME, datetime_string() + ': ' + _(u'Minimum has updated.')) update_log() if status['level'] <= int( tank_options['water_minimum'] ) and mini and not options.manual_mode and status[ 'level'] > 2: # level value is lower if tank_options[ 'use_send_email']: # if email is enabled send = True # send mini = False if tank_options['use_stop']: # if stop scheduler set_stations_in_scheduler_off() log.info( NAME, datetime_string() + ' ' + _(u'ERROR: Water in Tank') + ' < ' + str(tank_options['water_minimum']) + ' ' + _(u'cm') + _(u'!')) delaytime = int(tank_options['delay_duration']) if delaytime > 0: # if there is no water in the tank and the stations stop, then we set the rain delay for this time for blocking rain_blocks[NAME] = datetime.datetime.now( ) + datetime.timedelta( hours=float(delaytime)) if level_in_tank > int( tank_options['water_minimum'] ) + 5 and not mini: # refresh send email if actual level > options minimum +5 mini = True if NAME in rain_blocks and level_in_tank > int( tank_options['water_minimum']): del rain_blocks[NAME] if tank_options['enable_log']: millis = int(round(time.time() * 1000)) interval = (tank_options['log_interval'] * 60000) if (millis - last_millis) > interval: last_millis = millis update_log() elif level_in_tank == -1 and sonic_cm == 0: # waiting for samples tempText = _('Waiting for samples') else: # error probe tempText = _('FAULT') log.clear(NAME) log.info( NAME, datetime_string() + ' ' + _(u'Water level: Error.')) if tank_options[ 'use_water_err'] and three_text: # if probe has error send email three_text = False log.info( NAME, datetime_string() + ' ' + _(u'ERROR: Water probe has fault?')) msg = '<b>' + _( u'Water Tank Monitor plug-in' ) + '</b> ' + '<br><p style="color:red;">' + _( u'System detected error: Water probe has fault?' ) + '</p>' msglog = _( u'Water Tank Monitor plug-in' ) + ': ' + _( u'System detected error: Water probe has fault?' ) try: from plugins.email_notifications import try_mail try_mail( msg, msglog, attachment=None, subject=tank_options['emlsubject'] ) # try_mail(text, logtext, attachment=None, subject=None) except Exception: log.error( NAME, _(u'Water Tank Monitor plug-in') + ':\n' + traceback.format_exc()) if tank_options['use_water_stop']: if NAME not in rain_blocks: set_stations_in_scheduler_off() delaytime = int(tank_options['delay_duration']) if delaytime > 0: # if probe has fault, then we set the rain delay for this time for blocking rain_blocks[NAME] = datetime.datetime.now( ) + datetime.timedelta( hours=float(delaytime)) if tank_options['enable_reg']: tempText += ', ' + regulation_text if tank_options['use_footer']: if tank_mon is not None: tank_mon.val = tempText.encode('utf8').decode( 'utf8') # value on footer self._sleep(3) else: if once_text: log.clear(NAME) log.info(NAME, _(u'Water tank monitor is disabled.')) once_text = False two_text = True last_level = 0 self._sleep(1) if send: msg = '<b>' + _( u'Water Tank Monitor plug-in' ) + '</b> ' + '<br><p style="color:red;">' + _( u'System detected error: Water Tank has minimum Water Level' ) + ': ' + str(tank_options['water_minimum']) + _( u'cm') + '.\n' + '</p>' msglog = _(u'Water Tank Monitor plug-in') + ': ' + _( u'System detected error: Water Tank has minimum Water Level' ) + ': ' + str( tank_options['water_minimum']) + _(u'cm') + '. ' send = False try: try_mail = None if tank_options['eplug'] == 0: # email_notifications from plugins.email_notifications import try_mail if tank_options[ 'eplug'] == 1: # email_notifications SSL from plugins.email_notifications_ssl import try_mail if try_mail is not None: try_mail( msg, msglog, attachment=None, subject=tank_options['emlsubject'] ) # try_mail(text, logtext, attachment=None, subject=None) except Exception: log.info( NAME, _(u'E-mail not send! The Email Notifications plug-in is not found in OSPy or not correctly setuped.' )) log.error( NAME, _(u'Water Tank Monitor plug-in') + ':\n' + traceback.format_exc()) except Exception: log.clear(NAME) log.error( NAME, _(u'Water Tank Monitor plug-in') + ':\n' + traceback.format_exc()) self._sleep(60)
def GET(self): from ospy import server qdict = web.input() stop_all = get_input(qdict, 'stop_all', False, lambda x: True) scheduler_enabled = get_input(qdict, 'scheduler_enabled', None, lambda x: x == '1') manual_mode = get_input(qdict, 'manual_mode', None, lambda x: x == '1') rain_block = get_input(qdict, 'rain_block', None, float) level_adjustment = get_input(qdict, 'level_adjustment', None, float) toggle_temp = get_input(qdict, 'toggle_temp', False, lambda x: True) if stop_all: if not options.manual_mode: options.scheduler_enabled = False programs.run_now_program = None run_once.clear() log.finish_run(None) stations.clear() if scheduler_enabled is not None: options.scheduler_enabled = scheduler_enabled if manual_mode is not None: options.manual_mode = manual_mode if rain_block is not None: options.rain_block = datetime.datetime.now() + datetime.timedelta(hours=rain_block) if level_adjustment is not None: options.level_adjustment = level_adjustment / 100 if toggle_temp: options.temp_unit = "F" if options.temp_unit == "C" else "C" set_to = get_input(qdict, 'set_to', None, int) sid = get_input(qdict, 'sid', 0, int) - 1 set_time = get_input(qdict, 'set_time', 0, int) if set_to is not None and 0 <= sid < stations.count() and options.manual_mode: if set_to: # if status is on start = datetime.datetime.now() new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': "Manual", 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': start + datetime.timedelta(days=3650), 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } if set_time > 0: # if an optional duration time is given new_schedule['end'] = datetime.datetime.now() + datetime.timedelta(seconds=set_time) log.start_run(new_schedule) stations.activate(new_schedule['station']) else: # If status is off stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) self._redirect_back()
def run(self): Temperature = 0 Humidity = 0 last_millis = 0 # timer for save log var1 = True # Auxiliary variable for once on var2 = True # Auxiliary variable for once off air_temp = None if plugin_options['use_footer']: air_temp = showInFooter( ) # instantiate class to enable data in footer air_temp.button = "air_temp_humi/settings" # button redirect on footer air_temp.label = _(u'Temperature') # label on footer regulation_text = '' #flow = showOnTimeline() # instantiate class to enable data display #flow.unit = _(u'Liters') #flow.val = 10 #flow.clear while not self._stop_event.is_set(): try: if plugin_options['enabled']: # if plugin is enabled log.clear(NAME) log.info(NAME, datetime_string()) tempText = "" if plugin_options[ 'enable_dht']: # if DHTxx probe is enabled try: result = 1 # 1=ERR_MISSING_DATA if plugin_options['dht_type'] == 0: # DHT11 result = instance.read() if plugin_options['dht_type'] == 1: # DHT22 result = instance22.read() if result.is_valid( ): # 0=ERR_NO_ERROR, 1=ERR_MISSING_DATA, 2=ERR_CRC Temperature = result.temperature Humidity = result.humidity global tempDHT, humiDHT tempDHT = Temperature humiDHT = Humidity except: log.clear(NAME) log.info(NAME, datetime_string()) if plugin_options['dht_type'] == 0: # DHT11 log.info(NAME, _(u'DHT11 data is not valid')) tempText += ' ' + _(u'DHT11 data is not valid') if plugin_options['dht_type'] == 1: # DHT22 log.info(NAME, _(u'DHT22 data is not valid')) tempText += ' ' + _(u'DHT22 data is not valid') if Humidity and Temperature != 0: self.status['temp'] = Temperature self.status['humi'] = Humidity log.info( NAME, _(u'Temperature') + ' ' + _(u'DHT') + ': ' + u'%.1f \u2103' % Temperature) log.info( NAME, _(u'Humidity') + ' ' + _(u'DHT') + ': ' + u'%.1f' % Humidity + ' %RH') tempText += ' ' + _( u'DHT' ) + ': ' + u'%.1f \u2103' % Temperature + ' ' + u'%.1f' % Humidity + ' %RH' + ' ' if plugin_options['enabled_reg']: log.info(NAME, regulation_text) station = stations.get( plugin_options['control_output']) if plugin_options[ 'enabled_reg']: # if regulation is enabled if Humidity > (plugin_options['humidity_on'] + plugin_options['hysteresis'] / 2) and var1 is True: start = datetime.datetime.now() sid = station.index end = datetime.datetime.now( ) + datetime.timedelta( seconds=plugin_options['reg_ss'], minutes=plugin_options['reg_mm']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _('Air Temperature'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) var1 = False var2 = True self.status['outp'] = 1 regulation_text = datetime_string( ) + ' ' + _( u'Regulation set ON.' ) + ' ' + ' (' + _('Output') + ' ' + str( station.index + 1) + ').' update_log(self.status) if Humidity < (plugin_options['humidity_off'] - plugin_options['hysteresis'] / 2) and var2 is True: sid = station.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) var1 = True var2 = False self.status['outp'] = 0 regulation_text = datetime_string( ) + ' ' + _( u'Regulation set OFF.' ) + ' ' + ' (' + _('Output') + ' ' + str( station.index + 1) + ').' update_log(self.status) if plugin_options[ 'ds_enabled']: # if in plugin is enabled DS18B20 DS18B20_read_data( ) # get read DS18B20 temperature data to global tempDS[xx] tempText += _(u'DS') + ': ' for i in range(0, plugin_options['ds_used']): self.status['DS%d' % i] = tempDS[i] log.info( NAME, _(u'Temperature') + ' ' + _(u'DS') + str(i + 1) + ' (' + u'%s' % plugin_options['label_ds%d' % i] + '): ' + u'%.1f \u2103' % self.status['DS%d' % i]) tempText += u' %s' % plugin_options[ 'label_ds%d' % i] + u' %.1f \u2103' % self.status['DS%d' % i] if plugin_options['enabled_reg']: tempText += ' ' + regulation_text if plugin_options['use_footer']: if air_temp is not None: if is_python2(): air_temp.val = tempText # value on footer else: air_temp.val = tempText.encode('utf8').decode( 'utf8') # value on footer if plugin_options['enable_log']: # enabled logging millis = int(round(time.time() * 1000)) interval = (plugin_options['log_interval'] * 60000) if (millis - last_millis) > interval: last_millis = millis update_log(self.status) self._sleep(5) except Exception: log.error( NAME, _(u'Air Temperature and Humidity Monitor plug-in') + ':\n' + traceback.format_exc()) self._sleep(60)
def _check_schedule(): current_time = datetime.datetime.now() check_start = current_time - datetime.timedelta(days=1) check_end = current_time + datetime.timedelta(days=1) rain = not options.manual_mode and ( rain_blocks.block_end() > datetime.datetime.now() or inputs.rain_sensed()) active = log.active_runs() for entry in active: ignore_rain = stations.get(entry['station']).ignore_rain if entry['end'] <= current_time or (rain and not ignore_rain and not entry['blocked'] and not entry['manual']): log.finish_run(entry) if not entry['blocked']: stations.deactivate(entry['station']) if not options.manual_mode: schedule = predicted_schedule(check_start, check_end) #import pprint #logging.debug("Schedule: %s", pprint.pformat(schedule)) for entry in schedule: if entry['start'] <= current_time < entry['end']: log.start_run(entry) if not entry['blocked']: stations.activate(entry['station']) if stations.master is not None: master_on = False # It's easy if we don't have to use delays: if options.master_on_delay == options.master_off_delay == 0: for entry in active: if not entry['blocked'] and stations.get( entry['station']).activate_master: master_on = True break else: # In manual mode we cannot predict, we only know what is currently running and the history if options.manual_mode: active = log.finished_runs() + active else: active = combined_schedule(check_start, check_end) for entry in active: if not entry['blocked'] and stations.get( entry['station']).activate_master: if entry['start'] + datetime.timedelta(seconds=options.master_on_delay) \ <= current_time < \ entry['end'] + datetime.timedelta(seconds=options.master_off_delay): master_on = True break if stations.master is not None: master_station = stations.get(stations.master) if master_on != master_station.active: master_station.active = master_on if options.master_relay: outputs.relay_output = master_on if stations.master_two is not None: master_two_on = False # It's easy if we don't have to use delays: if options.master_on_delay_two == options.master_off_delay_two == 0: for entry in active: if not entry['blocked'] and stations.get( entry['station']).activate_master_two: master_two_on = True break else: # In manual mode we cannot predict, we only know what is currently running and the history if options.manual_mode: active = log.finished_runs() + active else: active = combined_schedule(check_start, check_end) for entry in active: if not entry['blocked'] and stations.get( entry['station']).activate_master_two: if entry['start'] + datetime.timedelta(seconds=options.master_on_delay) \ <= current_time < \ entry['end'] + datetime.timedelta(seconds=options.master_off_delay): master_two_on = True break if stations.master_two is not None: master_station_two = stations.get(stations.master_two) if master_two_on != master_station_two.active: master_station_two.active = master_two_on
def on_message(client, userdata, message): log.clear(NAME) log.info(NAME, datetime_string() + ' ' + _('Message received') + ': ' + str(message.payload.decode("utf-8"))) #print("Message topic=",message.topic) #print("Message qos=",message.qos) #print("Message retain flag=",message.retain) try: cmd = json.loads(message.payload) except: cmd = [] status = "RunOnce Error" client.publish(plugin_options['publish_up_down'], status) pass try: log.info(NAME, datetime_string() + ' ' + _(u'Try-ing to processing command.')) num_sta = options.output_count if type(cmd) is list: # cmd is list if len(cmd) < num_sta: log.info(NAME, datetime_string() + ' ' + _(u'Not enough stations specified, assuming first {} of {}').format(len(cmd), num_sta)) rovals = cmd + ([0] * (num_sta - len(cmd))) elif len(cmd) > num_sta: log.info(NAME, datetime_string() + ' ' + _(u'Too many stations specified, truncating to {}').format(num_sta)) rovals = cmd[0:num_sta] else: rovals = cmd elif type(cmd) is dict: # cmd is dictionary rovals = [0] * num_sta snames = station_names() # Load station names from file jnames = json.loads(snames) # Load as json for k, v in list(cmd.items()): if k not in snames: # station name in dict is not in OSPy stations name (ERROR) log.warning(NAME, _(u'No station named') + (u': %s') % k) else: # station name in dict is in OSPy stations name (OK) # v is value for time, k is station name in dict rovals[jnames.index(k)] = v else: log.error(NAME, datetime_string() + ' ' + _(u'Unexpected command') + (u': %s') % message.payload) rovals = None status = "RunOnce Error" client.publish(plugin_options['publish_up_down'], status) if rovals is not None and any(rovals): for i in range(0, len(rovals)): sid = i start = datetime.datetime.now() try: end = datetime.datetime.now() + datetime.timedelta(seconds=int(rovals[i])) except: end = datetime.datetime.now() log.error(NAME, _(u'MQTT Run-once plug-in') + ':\n' + traceback.format_exc()) pass new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _(u'MQTT Run-once'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if int(rovals[i]) < 1: # station has no time for run (stoping) stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) status = "RunOnce Processing" client.publish(plugin_options['publish_up_down'], status) except Exception: log.clear(NAME) log.error(NAME, _(u'MQTT Run-once plug-in') + ':\n' + traceback.format_exc()) status = "RunOnce Error" client.publish(plugin_options['publish_up_down'], status) pass
def on_message(client, userdata, message): log.clear(NAME) log.info( NAME, datetime_string() + ' ' + _('Message received') + ': ' + str(message.payload.decode("utf-8"))) #print("Message topic=",message.topic) #print("Message qos=",message.qos) #print("Message retain flag=",message.retain) if plugin_options["use_mqtt_secondary"]: if not options.manual_mode: # check operation status log.info( NAME, datetime_string() + ' ' + _('You must this OSPy switch to manual mode!')) return if inputs.rain_sensed(): # check rain sensor log.info( NAME, datetime_string() + ' ' + _('Skipping command, rain sense is detected!')) return if rain_blocks.seconds_left(): # check rain delay log.info( NAME, datetime_string() + ' ' + _('Skipping command, rain delay is activated!')) return try: rec_data = str(message.payload) cmd = json.loads(rec_data) except ValueError as e: log.info(NAME, _('Could not decode command:') + ':\n' + message.payload, e) return first = int( plugin_options["first_station"]) - 1 # first secondary station count = int(plugin_options["station_count"]) # count secondary station try: for i in range( first, first + count): # count of station (example on main OSPy: 5 to 10) zone = cmd[i]["status"] # "off" or "on" state #station = cmd[i]["station"] #name = cmd[i]["name"] #print station, name, zone sid = i - first if sid <= stations.count(): # local station size check if zone == "on": start = datetime.datetime.now() mqn = _('MQTT Manual') new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': mqn, 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': start + datetime.timedelta(days=3650), 'uid': '%s-%s-%d' % (str(start), mqn, sid), 'usage': stations.get(sid).usage } # if an optional duration time is given #set_time = xxx second #new_schedule['end'] = datetime.datetime.now() + datetime.timedelta(seconds=set_time) log.start_run(new_schedule) stations.activate(new_schedule['station']) if zone == "off": stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == i: log.finish_run(interval) else: log.error( NAME, _('MQTT plug-in') + ':\n' + _('Setup stations count is smaler! Set correct first station and station count.' )) except Exception: log.error(NAME, _('MQTT plug-in') + ':\n' + traceback.format_exc()) time.sleep(1)
def run(self): temperature_ds = [-127, -127, -127, -127, -127, -127] msg_a_on = True msg_a_off = True msg_b_on = True msg_b_off = True msg_c_on = True msg_c_off = True temp_sw = None if plugin_options['use_footer']: temp_sw = showInFooter( ) # instantiate class to enable data in footer temp_sw.button = "temperature_switch/settings" # button redirect on footer temp_sw.label = _(u'Temperature Switch') # label on footer millis = int(round( time.time() * 1000)) # timer for clearing status on the web pages after 60 sec last_millis = millis a_state = -1 # for state in footer (-1 disable regulation A, 0 = Aoff, 1 = Aon) b_state = -1 c_state = -1 helper_text = '' while not self._stop_event.is_set(): try: try: from plugins.air_temp_humi import plugin_options as air_temp_data plugin_options['ds_name_0'] = air_temp_data['label_ds0'] plugin_options['ds_name_1'] = air_temp_data['label_ds1'] plugin_options['ds_name_2'] = air_temp_data['label_ds2'] plugin_options['ds_name_3'] = air_temp_data['label_ds3'] plugin_options['ds_name_4'] = air_temp_data['label_ds4'] plugin_options['ds_name_5'] = air_temp_data['label_ds5'] plugin_options['ds_count'] = air_temp_data['ds_used'] from plugins.air_temp_humi import DS18B20_read_probe temperature_ds = [ DS18B20_read_probe(0), DS18B20_read_probe(1), DS18B20_read_probe(2), DS18B20_read_probe(3), DS18B20_read_probe(4), DS18B20_read_probe(5) ] except: log.error( NAME, _(u'Unable to load settings from Air Temperature and Humidity Monitor plugin! Is the plugin Air Temperature and Humidity Monitor installed and set up?' )) self._sleep(60) # regulation A if plugin_options['enabled_a']: ds_a_on = temperature_ds[plugin_options['probe_A_on']] ds_a_off = temperature_ds[plugin_options['probe_A_off']] station_a = stations.get( plugin_options['control_output_A']) if ds_a_on > plugin_options[ 'temp_a_on']: # if DSxx > temperature AON a_state = 1 if msg_a_on: msg_a_on = False msg_a_off = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_a.name + ' ' + _(u'was turned on.')) start = datetime.datetime.now() sid = station_a.index end = datetime.datetime.now() + datetime.timedelta( seconds=plugin_options['reg_ss_a'], minutes=plugin_options['reg_mm_a']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _('Temperature Switch A'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if ds_a_off < plugin_options[ 'temp_a_off']: # if DSxx < temperature AOFF a_state = 0 if msg_a_off: msg_a_off = False msg_a_on = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_a.name + ' ' + _(u'was turned off.')) sid = station_a.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) else: a_state = -1 # regulation B if plugin_options['enabled_b']: ds_b_on = temperature_ds[plugin_options['probe_B_on']] ds_b_off = temperature_ds[plugin_options['probe_B_off']] station_b = stations.get( plugin_options['control_output_B']) if ds_b_on > plugin_options[ 'temp_b_on']: # if DSxx > temperature BON b_state = 1 if msg_b_on: msg_b_on = False msg_b_off = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_b.name + ' ' + _(u'was turned on.')) start = datetime.datetime.now() sid = station_b.index end = datetime.datetime.now() + datetime.timedelta( seconds=plugin_options['reg_ss_b'], minutes=plugin_options['reg_mm_b']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _('Temperature Switch B'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if ds_b_off < plugin_options[ 'temp_b_off']: # if DSxx < temperature BOFF b_state = 0 if msg_b_off: msg_b_off = False msg_b_on = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_b.name + ' ' + _(u'was turned off.')) sid = station_b.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) else: b_state = -1 # regulation C if plugin_options['enabled_c']: ds_c_on = temperature_ds[plugin_options['probe_C_on']] ds_c_off = temperature_ds[plugin_options['probe_C_off']] station_c = stations.get( plugin_options['control_output_C']) if ds_c_on > plugin_options[ 'temp_c_on']: # if DSxx > temperature CON c_state = 1 if msg_c_on: msg_c_on = False msg_c_off = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_c.name + ' ' + _(u'was turned on.')) start = datetime.datetime.now() sid = station_c.index end = datetime.datetime.now() + datetime.timedelta( seconds=plugin_options['reg_ss_c'], minutes=plugin_options['reg_mm_c']) new_schedule = { 'active': True, 'program': -1, 'station': sid, 'program_name': _('Temperature Switch C'), 'fixed': True, 'cut_off': 0, 'manual': True, 'blocked': False, 'start': start, 'original_start': start, 'end': end, 'uid': '%s-%s-%d' % (str(start), "Manual", sid), 'usage': stations.get(sid).usage } log.start_run(new_schedule) stations.activate(new_schedule['station']) if ds_c_off < plugin_options[ 'temp_c_off']: # if DSxx < temperature COFF c_state = 0 if msg_c_off: msg_c_off = False msg_c_on = True log.info( NAME, datetime_string() + ' ' + u'%s' % station_c.name + ' ' + _(u'was turned off.')) sid = station_c.index stations.deactivate(sid) active = log.active_runs() for interval in active: if interval['station'] == sid: log.finish_run(interval) else: c_state = -1 # footer text tempText = ' ' if a_state == 0: tempText += _(u'Regulation A set OFF') + '. ' if a_state == 1: tempText += _(u'Regulation A set ON') + '. ' if b_state == 0: tempText += ' ' + _(u'Regulation B set OFF') + '. ' if b_state == 1: tempText += ' ' + _(u'Regulation B set ON') + '. ' if c_state == 0: tempText += ' ' + _(u'Regulation C set OFF') + '. ' if c_state == 1: tempText += ' ' + _(u'Regulation C set ON') + '. ' if (a_state == -1) and (b_state == -1) and (c_state == -1): tempText = _(u'No change') + '. ' if plugin_options['use_footer']: if temp_sw is not None: if tempText != helper_text: temp_sw.val = tempText.encode('utf8').decode( 'utf8') # value on footer helper_text = tempText self._sleep(2) millis = int(round(time.time() * 1000)) if (millis - last_millis ) > 60000: # 60 second to clearing status on the webpage last_millis = millis log.clear(NAME) except Exception: log.error( NAME, _(u'Temperature Switch plug-in') + ':\n' + traceback.format_exc()) self._sleep(60)