def reboot(wait=1, block=False): """ Reboots the Raspberry Pi from a new thread. @type wait: int @param wait: length of time to wait before rebooting @type block: bool @param block: If True, clear output and perform reboot after wait. Set to True at start of thread (recursive). """ if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print _('Rebooting...') except Exception: pass subprocess.Popen(['reboot']) else: t = Thread(target=reboot, args=(wait, True)) t.start()
def sip_begin(): ######################################################### #### Code to import all webpages and plugin webpages #### import plugins try: print _('plugins loaded:') except Exception: pass for name in plugins.__all__: print ' ', name gv.plugin_menu.sort(key=lambda entry: entry[0]) # Keep plugin manager at top of menu try: for i, item in enumerate(gv.plugin_menu): if '/plugins' in item: gv.plugin_menu.pop(i) except Exception: pass thread.start_new_thread(timing_loop, ()) if gv.use_gpio_pins: set_output() app.notfound = lambda: web.seeother('/') app.run()
def restart(wait=1, block=False): """ Restarts the software from a new thread. Set to True at start of thread (recursive). """ if block: report_restart() from gpio_pins import set_output gv.srvals = [0] * (gv.sd[u"nst"]) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print(_(u"Restarting...")) except Exception: pass gv.restarted = 0 pid = os.getpid() command = u"systemctl status " + str(pid) output = str(subprocess.check_output(command.split())) unit_name = output.split()[1] command = u"systemctl restart " + unit_name subprocess.Popen(command.split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def poweroff(wait=1, block=False): """ Powers off the Raspberry Pi from a new thread. @type wait: int or float @param wait: number of seconds to wait before rebooting @type block: bool @param block: If True, clear output and perform reboot after wait. Set to True at start of thread (recursive). """ if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print _('Powering off...') except Exception: pass subprocess.Popen(['poweroff']) else: t = Thread(target=poweroff, args=(wait, True)) t.start()
def set_stations(virt): """ Astivate stations associated with a virtual station. Selected stations wil run concurrently. """ global skip # prevent endless recursion if not skip: vid = ((gv.sd['nbrd'] - 1) * 8) + virt print("ready to set stations uaing stations ", com_stations[str(vid)]) # - test for b in range(gv.sd[u"nbrd"] - 1): stn_list = [int(i) - 1 for i in com_stations[str(vid)].split(",")] for sid in stn_list: gv.srvals[ sid] = 1 # used to turn zones on or off (list of one byte per station, 1 = turn on, 0 = turn off) gv.sbits[ b] |= 1 << sid # station bits, used to display stations that are on in UI (list of bytes, one byte per board) gv.ps[sid][ 0] = 1 # program schedule used for UI display (list of 2 element lists i.e. [program number, duration]) if not gv.sd[u'mm']: gv.sbits[ b] &= 1 << vid # station bits, used to display stations that are on in UI (list of bytes, one byte per board) gv.rs[sid][1] = gv.rs[vid][ 1] # run schedule (list [scheduled start time, scheduled stop time, duration, program number]) skip = 1 set_output() else: skip = 0
def restart(wait=1, block=False): """ Restarts the software from a new thread. @type wait: int @param wait: length of time to wait before rebooting @type block: bool @param block: If True, clear output and perform reboot after wait. Set to True at start of thread (recursive). """ if block: report_restart() from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: gv.logger.info(_('Restarting...')) except Exception: pass subprocess.Popen('service sip restart'.split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def GET(self): qdict = web.input() if u"rsn" in qdict and qdict[u"rsn"] == u"1": stop_stations() raise web.seeother(u"/") if u"en" in qdict and qdict[u"en"] == u"": qdict[u"en"] = u"1" # default elif u"en" in qdict and qdict[u"en"] == u"0": gv.srvals = [0] * (gv.sd[u"nst"]) # turn off all stations set_output() if u"mm" in qdict and qdict[u"mm"] == u"0": clear_mm() if u"rd" in qdict and qdict[u"rd"] != u"0" and qdict[u"rd"] != "": gv.sd[u"rd"] = int(float(qdict[u"rd"])) gv.sd[u"rdst"] = int( gv.now + gv.sd[u"rd"] * 3600 ) # + 1 # +1 adds a smidge just so after a round trip the display hasn"t already counted down by a minute. stop_onrain() elif u"rd" in qdict and qdict[u"rd"] == u"0": gv.sd[u"rdst"] = 0 for key in list(qdict.keys()): try: gv.sd[key] = int(qdict[key]) except Exception as e: report_error(u"change_values Exception", e) pass jsave(gv.sd, u"sd") report_value_change() raise web.seeother(u"/") # Send browser back to home page
def process_actions(): global logged_internal_error if len(actions) > 10 and not logged_internal_error: try: gv.plugin_data['te']['tesender'].try_mail( 'Internal error', 'Action list likely too long len: ' + str(len(actions))) except: log_event('action list email send failed') log_event('Action list likely too long len: ' + str(len(actions))) for a in actions: log_event('action time: ' + str(a['time']) + ' what: ' + a['action']['what']) logged_internal_error = True for i, a in enumerate(actions[:]): if a['time'] > gv.now: # actions are sorted in time break else: action = a['action'] try: if action['what'] == 'set_heatpump_mode': set_heatpump_mode(action['mode'], False) elif action['what'] == 'set_heatpump_pump_mode': set_heatpump_pump_mode(action['mode'], False) elif action['what'] == 'set_boiler_mode': set_boiler_mode(action['mode'], False) elif action['what'] == 'set_valve_change': amount = action['valve_change_percent'] amount = min(amount, 100) amount = max(amount, -100) if amount == 0: # stop valve movement # log_event('stop valve') gv.srvals[close_ret] = 0 gv.srvals[open_ret] = 0 elif amount < 0: # more return, less buffer tank # assume 100 seconds to fully move valve, so each amount request is actually a second insert_action(gv.now - int(amount), { 'what': 'set_valve_change', 'valve_change_percent': 0 }) gv.srvals[close_ret] = 0 gv.srvals[open_ret] = 1 log_event('more return water: ' + str(-int(amount)) + '%') else: # less return, more buffer tank insert_action(gv.now + int(amount), { 'what': 'set_valve_change', 'valve_change_percent': 0 }) gv.srvals[close_ret] = 1 gv.srvals[open_ret] = 0 log_event('more buffer tank water: ' + str(int(amount)) + '%') set_output() except Exception as ex: log_event('Unexpected action: ' + action['what'] + ' ex: ' + str(ex)) del actions[i]
def restart(wait=1, block=False): """ Restarts the software from a new thread. Set to True at start of thread (recursive). """ if block: report_restart() from gpio_pins import set_output gv.srvals = [0] * (gv.sd[u"nst"]) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print(_(u"Restarting...")) except Exception: pass gv.restarted = 0 if six.PY2: subprocess.Popen(u"systemctl restart sip.service".split()) elif six.PY3: subprocess.Popen(u"systemctl restart sip3.service".split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def GET(self): qdict = web.input() print 'qdict: ', qdict if 'rsn' in qdict and qdict['rsn'] == '1': stop_stations() raise web.seeother('/') if 'en' in qdict and qdict['en'] == '': qdict['en'] = '1' # default elif 'en' in qdict and qdict['en'] == '0': gv.srvals = [0] * (gv.sd['nst']) # turn off all stations set_output() if 'mm' in qdict and qdict['mm'] == '0': clear_mm() if 'rd' in qdict and qdict['rd'] != '0' and qdict['rd'] != '': gv.sd['rd'] = int(float(qdict['rd'])) gv.sd['rdst'] = int( gv.now + gv.sd['rd'] * 3600 ) # + 1 # +1 adds a smidge just so after a round trip the display hasn't already counted down by a minute. stop_onrain() elif 'rd' in qdict and qdict['rd'] == '0': gv.sd['rdst'] = 0 for key in qdict.keys(): try: gv.sd[key] = int(qdict[key]) except Exception: pass jsave(gv.sd, 'sd') report_value_change() raise web.seeother('/') # Send browser back to home page
def set_boiler_mode(md, remove=True): global boiler_mode, last_boiler_on, last_boiler_off if remove: remove_action({'what': 'set_boiler_mode', 'mode': 'any'}) if md == 'heating': gv.srvals[boiler_call] = 1 set_output() last_boiler_on = gv.now # gv.logger.info('set_boiler_mode ' + md + ' last_boiler_on: ' + str(last_boiler_on)) else: gv.srvals[boiler_call] = 0 set_output() if gv.sd['mode'] not in [ 'Boiler Only' ] and not boiler_through_buffer_tank: # put valve back to all buffer tank remove_action({'what': 'set_valve_change'}) insert_action(gv.now, { 'what': 'set_valve_change', 'valve_change_percent': 100 }) last_boiler_off = gv.now # gv.logger.info('set_boiler_mode ' + md + ' last_boiler_off: ' + str(last_boiler_off)) boiler_mode = md log_event('set_boiler_mode: ' + md)
def GET(self): qdict = web.input() print 'qdict: ', qdict if 'rsn' in qdict and qdict['rsn'] == '1': stop_stations() raise web.seeother('/') if 'en' in qdict and qdict['en'] == '': qdict['en'] = '1' # default elif 'en' in qdict and qdict['en'] == '0': gv.srvals = [0] * (gv.sd['nst']) # turn off all stations set_output() if 'mm' in qdict and qdict['mm'] == '0': clear_mm() if 'rd' in qdict and qdict['rd'] != '0' and qdict['rd'] != '': gv.sd['rd'] = int(float(qdict['rd'])) gv.sd['rdst'] = int(gv.now + gv.sd['rd'] * 3600) # + 1 # +1 adds a smidge just so after a round trip the display hasn't already counted down by a minute. stop_onrain() elif 'rd' in qdict and qdict['rd'] == '0': gv.sd['rdst'] = 0 for key in qdict.keys(): try: gv.sd[key] = int(qdict[key]) except Exception: pass jsave(gv.sd, 'sd') report_value_change() raise web.seeother('/') # Send browser back to home page
def restart(wait=1, block=False): """ Restarts the software from a new thread. @type wait: int @param wait: length of time to wait before rebooting @type block: bool @param block: If True, clear output and perform reboot after wait. Set to True at start of thread (recursive). """ if block: report_restart() from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print _('Restarting...') except Exception: pass gv.restarted = 0 subprocess.Popen('systemctl restart sip.service'.split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def restart(wait=1, block=False): if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() time.sleep(wait) print 'Restarting...' subprocess.Popen('service ospi restart'.split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def poweroff(wait=1, block=False): if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() time.sleep(wait) print 'Powering off...' subprocess.Popen(['poweroff']) else: t = Thread(target=poweroff, args=(wait, True)) t.start()
def reboot(wait=1, block=False): if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() time.sleep(wait) print 'Rebooting...' subprocess.Popen(['reboot']) else: t = Thread(target=reboot, args=(wait, True)) t.start()
def chatter(cct): stop_stations() t = 0 for cnt in range(150): t = 1 - t # toggle cct gv.srvals[cct] = t set_output() sleep(0.2) if stop: break # switch everything off stop_stations()
def GET(self): qdict = web.input() sid = get_input(qdict, u"sid", 0, int) - 1 set_to = get_input(qdict, u"set_to", None, int) set_time = get_input(qdict, u"set_time", 0, int) if set_to is None: if sid < 0: status = u"<!DOCTYPE html>\n" status += u"".join(str(x) for x in gv.srvals) return status elif sid < gv.sd[u"nbrd"] * 8: status = u"<!DOCTYPE html>\n" status += str(gv.srvals[sid]) return status else: return _(u"Station ") + str(sid + 1) + _(u" not found.") elif gv.sd[u"mm"]: if set_to: # if status is on if gv.sd[u"seq"]: if gv.sd["mas"]: # if a master is set for i in range(gv.sd[u"nst"]): if i != gv.sd["mas"] - 1: gv.srvals[i] = 0 gv.rs[i] = [0, 0, 0, 0] gv.ps[i] = [0, 0] set_output() sb_byte = (gv.sd["mas"] - 1) // 8 gv.sbits[sb_byte] = 1 << (gv.sd["mas"] - 1) % 8 for b in range(len(gv.sbits)): if b != sb_byte: gv.sbits[b] = 0 else: stop_stations() gv.rs[sid][0] = gv.now # set start time to current time if set_time > 0: # if an optional duration time is given gv.rs[sid][2] = set_time gv.rs[sid][1] = ( gv.rs[sid][0] + set_time ) # stop time = start time + duration else: gv.rs[sid][1] = float(u"inf") # stop time = infinity gv.rs[sid][3] = 99 # set program index gv.ps[sid][1] = set_time gv.sd[u"bsy"] = 1 time.sleep(1) else: # If status is off gv.rs[sid][1] = gv.now + 2 time.sleep(2) raise web.seeother(u"/") else: return _(u"Manual mode not active.")
def stop_stations(): """Stop all running stations, clear schedules.""" gv.srvals = [0] * (gv.sd['nst']) set_output() gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 return
def clear_mm(): """Clear manual mode settings.""" if gv.sd['mm']: gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.srvals = [0] * (gv.sd['nst']) set_output() return
def stop_onrain(): """Stop stations that do not ignore rain.""" for b in range(gv.sd['nbrd']): for s in range(8): sid = b * 8 + s # station index if gv.sd['ir'][b] & 1 << s: # if station ignores rain... continue elif not all(v == 0 for v in gv.rs[sid]): gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~1 << s# Clears stopped stations from display gv.ps[sid] = [0, 0] gv.rs[sid] = [0, 0, 0, 0] return
def stop_onrain(): """Stop stations that do not ignore rain.""" for b in range(gv.sd['nbrd']): for s in range(8): sid = b * 8 + s # station index if gv.sd['ir'][b] & 1 << s: # if station ignores rain... continue elif not all(v == 0 for v in gv.rs[sid]): gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~1 << s # Clears stopped stations from display gv.ps[sid] = [0, 0] gv.rs[sid] = [0, 0, 0, 0] return
def stop_stations(): """Stop all running stations, clear schedules.""" from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 return
def clear_mm(): """Clear manual mode settings.""" from gpio_pins import set_output if gv.sd['mm']: gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.srvals = [0] * (gv.sd['nst']) set_output() return
def poweroff(wait=1, block=False): if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() GPIO.cleanup() time.sleep(wait) try: print _('Powering off...') except Exception: pass subprocess.Popen(['poweroff']) else: t = Thread(target=poweroff, args=(wait, True)) t.start()
def clear_mm(): """ Clear manual mode settings and stop any running zones. """ from gpio_pins import set_output if gv.sd['mm']: gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.srvals = [0] * (gv.sd['nst']) set_output() return
def clear_mm(): """ Clear manual mode settings and stop any running zones. """ from gpio_pins import set_output if gv.sd[u"mm"]: gv.sbits = [0] * (gv.sd[u"nbrd"] + 1) gv.ps = [] for i in range(gv.sd[u"nst"]): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd[u"nst"]): gv.rs.append([0, 0, 0, 0]) gv.srvals = [0] * (gv.sd[u"nst"]) set_output() return
def process_actions(): global logged_internal_error if len(actions) > 10 and not logged_internal_error: email('Internal error', 'Action list likely too long len: ' + str(len(actions))) log_event('Action list likely too long len: ' + str(len(actions))) for a in actions: log_event('action time: ' + str(a['time']) + ' what: ' + a['action']['what']) logged_internal_error = True for i, a in enumerate(actions[:]): if a['time'] > gv.now: # actions are sorted in time break else: action = a['action'] try: if action['what'] == 'set_heatpump_mode': set_heatpump_mode(action['mode'], False) elif action['what'] == 'set_heatpump_pump_mode': set_heatpump_pump_mode(action['mode'], False) elif action['what'] == 'set_boiler_mode': set_boiler_mode(action['mode'], False) elif action['what'] == 'set_valve_change': amount = action['valve_change_percent'] amount = min(amount, 100) amount = max(amount, -100) if amount == 0: # stop valve movement # log_event('stop valve') gv.srvals[close_ret] = 0 gv.srvals[open_ret] = 0 elif amount < 0: # more return, less buffer tank # assume 100 seconds to fully move valve, so each amount request is actually a second insert_action(gv.now-int(amount), {'what':'set_valve_change', 'valve_change_percent':0}) gv.srvals[close_ret] = 0 gv.srvals[open_ret] = 1 log_event('more return water: ' + str(-int(amount)) + '%') else: # less return, more buffer tank insert_action(gv.now+int(amount), {'what':'set_valve_change', 'valve_change_percent':0}) gv.srvals[close_ret] = 1 gv.srvals[open_ret] = 0 log_event('more buffer tank water: ' + str(int(amount)) + '%') set_output() except Exception as ex: log_event('Unexpected action: ' + action['what'] + ' ex: ' + str(ex)) del actions[i]
def restart(wait=1, block=False): if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd['nst']) set_output() try: GPIO.cleanup() except Exception: pass time.sleep(wait) try: print _('Restarting...') except Exception: pass subprocess.Popen('service ospi restart'.split()) else: t = Thread(target=restart, args=(wait, True)) t.start()
def set_boiler_mode(md, remove=True): global boiler_mode, last_boiler_on, last_boiler_off if remove: remove_action({'what':'set_boiler_mode', 'mode':'any'}) if md == 'heating': gv.srvals[boiler_call] = 1 set_output() last_boiler_on = gv.now else: gv.srvals[boiler_call] = 0 set_output() if gv.sd['mode'] not in ['Boiler Only'] and not boiler_through_buffer_tank: # put valve back to all buffer tank remove_action({'what':'set_valve_change'}) insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':100}) last_boiler_off = gv.now boiler_mode = md log_event('set_boiler_mode: ' + md)
def set_stations(virt): """ Activate stations associated with a virtual station. Selected stations wil run concurrently. """ vid = ((gv.sd[u'nbrd'] - 1) * 8) + virt # vid = key of station group in com_stations dict. stn_list = [int(i) - 1 for i in com_stations[str(vid)].split(",")] for sid in stn_list: gv.srvals[sid] = 1 # set gv.srvals on for stations in this group for b in range(gv.sd[u"nbrd"] - 1): # don't include virtual stations for s in range(8): # for each station per board sidx = b * 8 + s if gv.srvals[sidx]: # If this station should be on gv.sbits[ b] |= 1 << s # station bits, used to display stations that are on in UI (list of bytes, one byte per board) gv.ps[sidx][0] = 1 gv.rs[sidx] = gv.rs[vid] if not gv.sd[u'mm']: # If under program control gv.ps[sidx][1] = gv.rs[vid][2] set_output()
def stop_onrain(): """ Stop stations that do not ignore rain. """ from gpio_pins import set_output do_set_output = False for b in range(gv.sd[u"nbrd"]): for s in range(8): sid = b * 8 + s # station index if gv.sd[u"ir"][b] & 1 << s: # if station ignores rain... continue elif not all(v == 0 for v in gv.rs[sid]): gv.srvals[sid] = 0 do_set_output = True gv.sbits[b] &= ~1 << s # Clears stopped stations from display gv.ps[sid] = [0, 0] gv.rs[sid] = [0, 0, 0, 0] if do_set_output: set_output() return
def reboot(wait=1, block=False): """ Reboots the Raspberry Pi from a new thread. Set to True at start of thread (recursive). """ if block: from gpio_pins import set_output gv.srvals = [0] * (gv.sd[u"nst"]) set_output() if gv.use_pigpio: pass else: GPIO.cleanup() time.sleep(wait) try: print(_(u"Rebooting...")) except Exception: pass subprocess.Popen([u"reboot"]) else: t = Thread(target=reboot, args=(wait, True)) t.start()
def chatter(cct): gv.srvals = [0]*8 #TODO read how many valves are in service, and which ones gpio.set_output() #TODO switch on gpio functions after debugging lv = 1 for cnt in range(150): #toggle cct gv.srvals[cct] ^= lv gpio.set_output() sleep(0.2) #switch everything off gv.srvals = [0]*8 gpio.set_output()
def set_heatpump_mode(md, remove=True): """Turn on dry3,4 for cooling; dry 2,4 for heating""" global heatpump_mode, last_heatpump_off, last_heatpump_on if remove: remove_action({'what': 'set_heatpump_mode', 'mode': 'any'}) if md == 'cooling': # gv.srvals[dry4] = 1 # set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 gv.srvals[dry2] = 0 # gv.srvals[dry3] = 1 set_output() heatpump_mode = 'cooling' set_heatpump_pump_mode('on') last_heatpump_on = gv.now elif md == 'heating': # gv.srvals[dry4] = 1 # set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 # gv.srvals[dry2] = 1 gv.srvals[dry3] = 0 set_output() heatpump_mode = 'heating' set_heatpump_pump_mode('on') last_heatpump_on = gv.now else: gv.srvals[dry4] = 0 set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 gv.srvals[dry2] = 0 gv.srvals[dry3] = 0 set_output() heatpump_mode = 'none' insert_action(gv.now + 2 * 60, { 'what': 'set_heatpump_pump_mode', 'mode': 'off' }) last_heatpump_off = gv.now
def set_heatpump_mode(md, remove=True): """Turn on dry3,4 for cooling; dry 2,4 for heating""" global heatpump_mode, last_heatpump_off, last_heatpump_on if remove: remove_action({'what':'set_heatpump_mode', 'mode':'any'}) if md == 'cooling': # gv.srvals[dry4] = 1 # set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 gv.srvals[dry2] = 0 # gv.srvals[dry3] = 1 set_output() heatpump_mode = 'cooling' set_heatpump_pump_mode('on') last_heatpump_on = gv.now elif md == 'heating': # gv.srvals[dry4] = 1 # set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 # gv.srvals[dry2] = 1 gv.srvals[dry3] = 0 set_output() heatpump_mode = 'heating' set_heatpump_pump_mode('on') last_heatpump_on = gv.now else: gv.srvals[dry4] = 0 set_output() time.sleep(.1) # make sure 4's state is set first gv.srvals[dry1] = 0 gv.srvals[dry2] = 0 gv.srvals[dry3] = 0 set_output() heatpump_mode = 'none' insert_action(gv.now+2*60, {'what':'set_heatpump_pump_mode', 'mode':'off'}) last_heatpump_off = gv.now
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ print 'Starting timing loop \n' last_min = 0 while True: # infinite loop gv.now = timegm(time.localtime()) # Current time based on local time from the Pi. updated once per second. gv.gmtnow = time.time() # Current gmt time (needed for client-side JS code). if gv.sd['en'] and not gv.sd['mm'] and (not gv.sd['bsy'] or not gv.sd['seq']): lt = time.gmtime(gv.now) if (lt[3] * 60) + lt[4] != last_min: # only check programs once a minute last_min = (lt[3] * 60) + lt[4] extra_adjustment = plugin_adjustment() for i, p in enumerate(gv.pd): # get both index and prog item # check if program time matches current time, is active, and has a duration if prog_match(p) and p[0] and p[6]: duration = p[6] * gv.sd['wl'] / 100 * extra_adjustment # program duration scaled by "water level" # check each station for boards listed in program up to number of boards in Options for b in range(len(p[7:7 + gv.sd['nbrd']])): for s in range(8): sid = b * 8 + s # station index if sid + 1 == gv.sd['mas']: continue # skip if this is master station if gv.srvals[sid]: # skip if currently on continue if p[7 + b] & 1 << s: # if this station is scheduled in this program if gv.sd['seq']: # sequential mode gv.rs[sid][2] = duration gv.rs[sid][3] = i + 1 # store program number for scheduling gv.ps[sid][0] = i + 1 # store program number for display gv.ps[sid][1] = duration else: # concurrent mode # If duration is shortter than any already set for this station if duration < gv.rs[sid][2]: continue else: gv.rs[sid][2] = duration gv.rs[sid][3] = i + 1 # store program number gv.ps[sid][0] = i + 1 # store program number for display gv.ps[sid][1] = duration schedule_stations(p[7:7 + gv.sd['nbrd']]) # turns on gv.sd['bsy'] if gv.sd['bsy']: for b in range(gv.sd['nbrd']): # Check each station once a second for s in range(8): sid = b * 8 + s # station index if gv.srvals[sid]: # if this station is on if gv.now >= gv.rs[sid][1]: # check if time is up gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~1 << s if gv.sd['mas'] - 1 != sid: # if not master, fill out log gv.ps[sid] = [0, 0] gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) gv.lrun[3] = gv.now log_run() gv.pon = None # Program has ended gv.rs[sid] = [0, 0, 0, 0] else: # if this station is not yet on if gv.rs[sid][0] <= gv.now < gv.rs[sid][1]: if gv.sd['mas'] - 1 != sid: # if not master gv.srvals[sid] = 1 # station is turned on set_output() gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = gv.rs[sid][3] gv.ps[sid][1] = gv.rs[sid][2] + 1 # testing display if gv.sd['mas'] and gv.sd['mo'][b] & 1 << (s - (s / 8) * 80): # Master settings masid = gv.sd['mas'] - 1 # master index gv.rs[masid][0] = gv.rs[sid][0] + gv.sd['mton'] gv.rs[masid][1] = gv.rs[sid][1] + gv.sd['mtoff'] gv.rs[masid][3] = gv.rs[sid][3] elif gv.sd['mas'] == sid + 1: gv.sbits[b] |= 1 << sid # (gv.sd['mas'] - 1) gv.srvals[masid] = 1 set_output() for s in range(gv.sd['nst']): if gv.rs[s][1]: # if any station is scheduled program_running = True gv.pon = gv.rs[s][3] # Store number of running program break program_running = False gv.pon = None if program_running: if gv.sd['urs'] and gv.sd['rs']: # Stop stations if use rain sensor and rain detected. stop_onrain() # Clear schedule for stations that do not ignore rain. for idx in range(len(gv.rs)): # loop through program schedule (gv.ps) if gv.rs[idx][2] == 0: # skip stations with no duration continue if gv.srvals[idx]: # If station is on, decrement time remaining display gv.ps[idx][1] -= 1 if not program_running: gv.srvals = [0] * (gv.sd['nst']) set_output() gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 if gv.sd['mas'] and (gv.sd['mm'] or not gv.sd['seq']): # handle master for maual or concurrent mode. mval = 0 for sid in range(gv.sd['nst']): bid = sid / 8 s = sid - bid * 8 if gv.sd['mas'] != sid + 1 and (gv.srvals[sid] and gv.sd['mo'][bid] & 1 << s): mval = 1 break if not mval: gv.rs[gv.sd['mas'] - 1][1] = gv.now # turn off master if gv.sd['urs']: check_rain() if gv.sd['rd'] and gv.now >= gv.sd['rdst']: # Check of rain delay time is up gv.sd['rd'] = 0 gv.sd['rdst'] = 0 # Rain delay stop time jsave(gv.sd, 'sd') time.sleep(1)
if web.config.get('_session') is None: web.config._session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'user': '******'}) template_globals = { 'gv': gv, 'str': str, 'eval': eval, 'session': web.config._session, 'json': json } template_render = web.template.render('templates', globals=template_globals, base='base') if __name__ == '__main__': ######################################################### #### Code to import all webpages and plugin webpages #### import plugins print 'plugins loaded:' for name in plugins.__all__: print ' ', name gv.plugin_menu.sort(key=lambda entry: entry[0]) set_output() thread.start_new_thread(timing_loop, ()) app.notfound = lambda: web.seeother('/') app.run()
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ try: print _('Starting timing loop') + '\n' except Exception: pass last_min = 0 while True: # infinite loop gv.nowt = time.localtime() # Current time as time struct. Updated once per second. gv.now = timegm(gv.nowt) # Current time as timestamp based on local time from the Pi. Updated once per second. if gv.sd['en'] and not gv.sd['mm'] and (not gv.sd['bsy'] or not gv.sd['seq']): if gv.now / 60 != last_min: # only check programs once a minute last_min = gv.now / 60 extra_adjustment = plugin_adjustment() for i, p in enumerate(gv.pd): # get both index and prog item # check if program time matches current time, is active, and has a duration if prog_match(p) and p[0] and p[6]: # check each station for boards listed in program up to number of boards in Options for b in range(len(p[7:7 + gv.sd['nbrd']])): for s in range(8): sid = b * 8 + s # station index if sid + 1 == gv.sd['mas']: continue # skip if this is master station if gv.srvals[sid]: # skip if currently on continue # station duration condionally scaled by "water level" if gv.sd['iw'][b] & 1 << s: duration_adj = 1.0 if gv.sd['idd'] == 1: duration = p[-1][sid] else: duration = p[6] else: duration_adj = gv.sd['wl'] / 100 * extra_adjustment if gv.sd['idd'] == 1: duration = p[-1][sid] * duration_adj else: duration = p[6] * duration_adj duration = int(round(duration)) # convert to int if p[7 + b] & 1 << s: # if this station is scheduled in this program if gv.sd['seq']: # sequential mode gv.rs[sid][2] = duration gv.rs[sid][3] = i + 1 # store program number for scheduling gv.ps[sid][0] = i + 1 # store program number for display gv.ps[sid][1] = duration else: # concurrent mode # If duration is shortter than any already set for this station if duration < gv.rs[sid][2]: continue else: gv.rs[sid][2] = duration gv.rs[sid][3] = i + 1 # store program number gv.ps[sid][0] = i + 1 # store program number for display gv.ps[sid][1] = duration schedule_stations(p[7:7 + gv.sd['nbrd']]) # turns on gv.sd['bsy'] if gv.sd['bsy']: for b in range(gv.sd['nbrd']): # Check each station once a second for s in range(8): sid = b * 8 + s # station index if gv.srvals[sid]: # if this station is on if gv.now >= gv.rs[sid][1]: # check if time is up gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~(1 << s) if gv.sd['mas'] - 1 != sid: # if not master, fill out log gv.ps[sid] = [0, 0] gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) gv.lrun[3] = gv.now log_run() gv.pon = None # Program has ended gv.rs[sid] = [0, 0, 0, 0] else: # if this station is not yet on if gv.rs[sid][0] <= gv.now < gv.rs[sid][1]: if gv.sd['mas'] - 1 != sid: # if not master gv.srvals[sid] = 1 # station is turned on set_output() gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = gv.rs[sid][3] gv.ps[sid][1] = gv.rs[sid][2] if gv.sd['mas'] and gv.sd['mo'][b] & 1 << (s - (s / 8) * 80): # Master settings masid = gv.sd['mas'] - 1 # master index gv.rs[masid][0] = gv.rs[sid][0] + gv.sd['mton'] gv.rs[masid][1] = gv.rs[sid][1] + gv.sd['mtoff'] gv.rs[masid][3] = gv.rs[sid][3] elif gv.sd['mas'] == sid + 1: gv.sbits[b] |= 1 << sid gv.srvals[masid] = 1 set_output() for s in range(gv.sd['nst']): if gv.rs[s][1]: # if any station is scheduled program_running = True gv.pon = gv.rs[s][3] # Store number of running program break program_running = False gv.pon = None if program_running: if gv.sd['urs'] and gv.sd['rs']: # Stop stations if use rain sensor and rain detected. stop_onrain() # Clear schedule for stations that do not ignore rain. for idx in range(len(gv.rs)): # loop through program schedule (gv.ps) if gv.rs[idx][2] == 0: # skip stations with no duration continue if gv.srvals[idx]: # If station is on, decrement time remaining display gv.ps[idx][1] -= 1 if not program_running: gv.srvals = [0] * (gv.sd['nst']) set_output() gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 if (gv.sd['mas'] # master is defined and (gv.sd['mm'] or not gv.sd['seq']) # manual or concurrent mode. ): stayon = 0 for octet in xrange(gv.sd['nbrd']): base = octet * 8 for s in xrange(8): stn = base + s if (gv.srvals[stn] # station is on and gv.rs[stn][1] >= gv.now # station has a stop time >= now and gv.sd['mo'][octet] & 1 << s # station activates master ): stayon = 1 break if not stayon: gv.rs[gv.sd['mas'] - 1][1] = gv.now # set master to turn off next cycle if gv.sd['urs']: check_rain() # in helpers.py if gv.sd['rd'] and gv.now >= gv.sd['rdst']: # Check if rain delay time is up gv.sd['rd'] = 0 gv.sd['rdst'] = 0 # Rain delay stop time jsave(gv.sd, 'sd') time.sleep(1)
def GET(self): qdict = web.input() if u"opw" in qdict and qdict[u"opw"] != u"": try: if password_hash(qdict[u"opw"]) == gv.sd[u"passphrase"]: if qdict[u"npw"] == u"": raise web.seeother(u"/vo?errorCode=pw_blank") elif qdict[u"cpw"] != u"" and qdict[u"cpw"] == qdict[ u"npw"]: gv.sd[ u"passphrase"] = password_hash( # Set new passphrase. qdict[u"npw"]) else: raise web.seeother(u"/vo?errorCode=pw_mismatch") else: raise web.seeother(u"/vo?errorCode=pw_wrong") except KeyError: pass for f in [u"name"]: if u"o" + f in qdict: gv.sd[f] = qdict[u"o" + f] for f in [u"loc", u"lang"]: if u"o" + f in qdict: if f not in gv.sd or gv.sd[f] != qdict[u"o" + f]: qdict[u"rstrt"] = u"1" # force restart with change gv.sd[f] = qdict[u"o" + f] if u"onbrd" in qdict: if int(qdict[u"onbrd"]) + 1 != gv.sd[u"nbrd"]: self.update_scount(qdict) gv.sd[u"nbrd"] = int(qdict[u"onbrd"]) + 1 gv.sd[u"nst"] = gv.sd[u"nbrd"] * 8 self.update_prog_lists(u"nbrd") if u"ohtp" in qdict: if u"htp" not in gv.sd or gv.sd[u"htp"] != int(qdict[u"ohtp"]): qdict[u"rstrt"] = u"1" # force restart with change in htp gv.sd[u"htp"] = int(qdict[u"ohtp"]) if u"oidd" in qdict: idd_int = 1 else: idd_int = 0 if idd_int != gv.sd[u"idd"]: gv.sd[u"idd"] = idd_int self.update_prog_lists(u"idd") if u"ohtip" in qdict: if u"htip" not in gv.sd or gv.sd[u"htip"] != qdict[u"ohtip"]: qdict[u"rstrt"] = u"1" # force restart with change in htip gv.sd[u"htip"] = qdict[u"ohtip"] for f in [u"sdt", u"mas", u"mton", u"mtoff", u"wl", u"lr", u"tz"]: if u"o" + f in qdict: if (f == u"mton" and int(qdict[u"o" + f]) < 0): # handle values less than zero (temp fix) raise web.seeother(u"/vo?errorCode=mton_minus") gv.sd[f] = int(qdict[u"o" + f]) for f in [ u"upas", u"tf", u"urs", u"seq", u"rst", u"lg", u"pigpio", u"alr", ]: if u"o" + f in qdict and (qdict[u"o" + f] == u"on" or qdict[u"o" + f] == u"1"): gv.sd[f] = 1 else: gv.sd[f] = 0 jsave(gv.sd, u"sd") report_option_change() if u"rbt" in qdict and qdict[u"rbt"] == u"1": gv.srvals = [0] * (gv.sd[u"nst"]) set_output() report_rebooted() reboot() if u"shutdown" in qdict and qdict[u"shutdown"] == u"1": gv.srvals = [0] * (gv.sd[u"nst"]) set_output() poweroff() if u"rstrt" in qdict and qdict[u"rstrt"] == u"1": restart(2) raise web.seeother(u"/restart") raise redirect_back()
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ last_min = 0 last_day = 0 last_master_station_running = 0 master_turn_on = 0 mton_delay = 0 gv.sd['bsy'] = 0 check_and_update_upnp() last_upnp_refresh = gv.now # Log the image and all the vsb board fw try: with open('data/version', 'r') as f: image_version = f.read() gv.logger.info('Image version: ' + image_version) except: pass boards = i2c.get_vsb_boards() for board, version in boards.items(): gv.logger.info('VSB Firmware for board: ' + str(board) + ' value: ' + hex(version)) for delay in range(15): time.sleep(1) # wait for ip addressing to settle but keep updating time gv.nowt = time.localtime() # Current time as time struct. Updated once per second. gv.now = timegm(gv.nowt) # Current time as timestamp based on local time from the Pi. Updated once per second. for i, p in enumerate(gv.pd): # get future instances of programs that recur but started earlier in the day if prog_match(p, True): schedule_recurring_instances(i) ip_countdown = 2 while True: # infinite loop gv.nowt = time.localtime() # Current time as time struct. Updated once per second. gv.now = timegm(gv.nowt) # Current time as timestamp based on local time from the Pi. Updated once per second. if gv.sd['en'] and not gv.sd['mm']: if gv.now // 60 != last_min: # only check programs once a minute last_min = gv.now // 60 update_radio_present() max_bd = -1 boards = i2c.get_vsb_boards() for bd, version in boards.items(): if bd not in gv.in_bootloader: try: max_bd = max(max_bd, bd) v = i2c_read(i2c.ADDRESS+bd, 0xc) # verify scratch value is as expected. Acts as a touch of the vsb too! if v != bd+16: gv.logger.critical('Main bad scratch value on board: ' + str(bd) + ' value: ' + str(v)) i2c_write(i2c.ADDRESS+bd, 0xc, bd+16) # write scratch register as keepalive except: gv.logger.critical('Cant access scratch register on board: ' + str(bd)) pass # read deadman debug register ignoring all errors. try: v = i2c_read(i2c.ADDRESS+bd, 0xd) if v != 0: gv.logger.critical('Deadman register triggered on board: ' + str(bd) + ' value: ' + str(v)) except: pass cur_bd = (gv.sd['nst']-gv.sd['radiost'])//8 if max_bd+1 > cur_bd: # ensure at nbrd captures all attached VSMs gv.logger.info('Changing nbrd based on attached boards: ' + str(max_bd+1)) adjust_gv_nbrd(max_bd+1) gv.sd['nst'] += 8*(max_bd+1-cur_bd) jsave(gv.sd, 'sd') cur_ip = get_ip() ext_ip_addr = get_external_ip() ip_countdown = 2 if cur_ip == gv.last_ip else ip_countdown-1 # when establishing bridge, wlan0 appears to drop then come back....just take a couple of iterations to # be sure we have an ip change. if ip_countdown == 0: ip_countdown = 2 # reset if gv.sd['master'] and (ext_ip_addr != gv.external_ip or cur_ip != gv.last_ip): gv.external_ip = ext_ip_addr try: # send email if ip addressing changed if gv.sd['teipchange'] and gv.plugin_data['te']['tesender']: subject = "Report from Irricloud" body = 'IP change. Local IP: ' + cur_ip if gv.sd['htp'] != 0 and gv.sd['htp'] != 80: body += ':' + str(gv.sd['htp']) body += ' External IP: ' + ext_ip_addr if gv.sd['external_htp'] != 0: body += ':' + str(gv.sd['external_htp']) gv.plugin_data['te']['tesender'].try_mail(subject, body) except: pass if cur_ip != gv.last_ip: gv.logger.info('IP changed from: ' + gv.last_ip + ' to: ' + cur_ip) gv.last_ip = cur_ip if cur_ip != "No IP Settings": # find router, set up upnp port mapping check_and_update_upnp(cur_ip) last_upnp_refresh = gv.now if gv.sd['upnp_refresh_rate'] > 0 and \ (gv.now-last_upnp_refresh)//60 >= gv.sd['upnp_refresh_rate']: check_and_update_upnp(cur_ip) last_upnp_refresh = gv.now cur_day = gv.now//86400 if cur_day != last_day: for i in range(gv.sd['nst']): for j in range(len(gv.rs[i])-1,0,-1): if gv.rs[i][j]['rs_stop_sec'] < gv.now: gv.logger.critical('Left over data on gv.rs['+str(i)+']') del gv.rs[i][j] elif gv.rs[i][j]['rs_stop_sec'] > gv.now + 86400: # indefinite program? gv.rs[i][j]['rs_stop_sec'] += 86400 # keep extending update_rs_order(i) last_day = cur_day for i, p in enumerate(gv.pd): # get both index and prog item if prog_match(p): gv.logger.debug('prog_match for program: ' + p[-1]) run_program(i) schedule_recurring_instances(i) for e in gv.recur[:]: # sorted by start times of recurring programs to run now_min = (gv.now%86400)//60 if e[0] <= now_min: try: gv.logger.debug('recur match for program: ' + gv.pd[e[1]][-1]) except: pass run_program(e[1]) # pid del gv.recur[0] # always deleting what is (now) first in list else: break if gv.sd['bsy']: with gv.rs_lock: program_running = False masid = gv.sd['mas']-1 for sid in range(gv.sd['nst']): # Check each station once a second b = sid >> 3 s = sid % 8 prog_id = gv.rs[sid][len(gv.rs[sid])-1]['rs_program_id'] p = None if prog_id >= len(gv.pd) else gv.pd[prog_id-1] if gv.now >= gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec'] and len(gv.rs[sid]) > 1: # check if time is up stop_station(sid, **{'stop_only_current':1}) elif gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec'] <= gv.now < gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec']: if (gv.sbits[b] & (1<<s)) == 0: # not yet displayed? duration = gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec'] - gv.now gv.logger.info('start station display sid: ' + str(sid+1) + ' for: ' + to_relative_time(duration)) gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = prog_id if gv.ps[sid][1] != duration: gv.logger.info('sip_loop ps_set: change ps sid: ' + str(sid+1) + ' from: ' + to_relative_time(gv.ps[sid][1])+ ' to: ' + to_relative_time(duration)) gv.ps[sid][1] = duration if p is None or (p[gv.p_flags]&2) == 0: # if not ban program gv.logger.info('turn on sid: ' + str(sid+1) + ' prog: ' + str(prog_id) + ' (ps set) dur: ' + to_relative_time(duration)) gv.srvals[sid] = 1 set_output() else: # already stopped what was running in schedule_stations gv.logger.info('turn on ban sid: ' + str(sid+1) + ' prog: ' + str(prog_id) + ' (ps set) dur: ' + to_relative_time(duration)) if sid == gv.sd['mas']-1: # when we turn on master, start mton countdown mton_delay = -gv.sd['mton'] elif gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec'] > gv.now and gv.ps[sid][0] == 0: duration = gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec'] - gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec'] gv.ps[sid][0] = prog_id if gv.ps[sid][1] != duration: gv.logger.info('sip_loop ps_change: change ps sid: ' + str(sid+1) + ' from: ' + to_relative_time(gv.ps[sid][1]) + ' to: ' + to_relative_time(duration)) gv.ps[sid][1] = duration gv.logger.info('future: ' + to_relative_time(gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec']) + ' turn on sid: ' + str(sid+1) + ' prog: ' + str(prog_id) + ' (ps set) dur: ' + to_relative_time(duration)) if masid >= 0 and sid != masid and gv.srvals[sid] and gv.sd['mo'][b]&(1<<s): # Master settings last_master_station_running = gv.now if len(gv.rs[sid]) > 1: # if any station is scheduled or on program_running = True # delays may have screwed up master scheduling. # If a station requiring master is running and master is not started, start it. if masid >= 0 and gv.srvals[masid] == 0: if master_turn_on == 0 and last_master_station_running == gv.now: master_turn_on = last_master_station_running + gv.sd['mton'] if master_turn_on != 0 and master_turn_on <= gv.now: gv.logger.info('turn on master without prescheduling mton: ' + str(master_turn_on)) gv.sbits[masid>>3] |= 1 << (masid%8) # Set display to on gv.ps[masid][0] = 98 gv.ps[masid][1] = 0 gv.srvals[masid] = 1 set_output() master_turn_on = 0 # If no station requiring master is running and master is not stopped, stop it. if masid >= 0 and gv.srvals[masid] == 1: if mton_delay >= 0: mton_delay -= 1 if (mton_delay < 0 and # allow for windown where master starts early last_master_station_running < gv.now and ((gv.sd['mtoff'] <= 0 and last_master_station_running >= gv.now + gv.sd['mtoff']) or \ (gv.sd['mtoff'] > 0 and last_master_station_running + gv.sd['mtoff'] <= gv.now))): gv.logger.info('turn off master without prescheduling') stop_station(masid, **{'stop_active':1}) mton_delay = 0 else: program_running = True # give time for master to shut down if program_running: # todo check stop_onrain for ban programs if gv.sd['urs'] and gv.sd['rs']: # Stop stations if use rain sensor and rain detected. stop_onrain() # Clear schedule for stations that do not ignore rain. for sid in range(len(gv.rs)): # loop through program schedule (gv.ps) if (gv.sbits[sid>>3] & (1<<(sid%8))) != 0: # If station is on, decrement time remaining display if gv.ps[sid][1] < 86400: # dont reduce indefinite program if gv.ps[sid][1] == -1: gv.logger.critical('sip negative ps decrement sid: ' + str(sid+1) + ' to: ' + to_relative_time(gv.ps[sid][1]) + \ ' start: ' + to_relative_time(gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec']) + \ ' stop: ' + to_relative_time(gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec'])) gv.ps[sid][1] -= 1 else: gv.logger.debug('sip_ indefinite program sid: ' + str(sid+1) + ' to: ' + to_relative_time(gv.ps[sid][1]) + \ ' start: ' + to_relative_time(gv.rs[sid][len(gv.rs[sid])-1]['rs_start_sec']) + \ ' stop: ' + to_relative_time(gv.rs[sid][len(gv.rs[sid])-1]['rs_stop_sec'])) pass if not program_running: gv.sd['bsy'] = 0 for sid in range(gv.sd['nst']): b = sid >> 3 s = sid % 8 if gv.srvals[sid]: gv.logger.critical('srval set with no program running sid: ' + str(sid+1)) if gv.sbits[b]&(1<<s): gv.logger.critical('sbits set with no program running sid: ' + str(sid+1)) if gv.ps[sid][0]: gv.logger.critical('ps[0] set with no program running sid: ' + str(sid+1)) if gv.ps[sid][1]: gv.logger.critical('ps[1] set with no program running sid: ' + str(sid+1)) if gv.sd['urs']: check_rain() # in helpers.py if gv.sd['rd'] and gv.now >= gv.sd['rdst']: # Check of rain delay time is up gv.sd['rd'] = 0 gv.sd['rdst'] = 0 # Rain delay stop time jsave(gv.sd, 'sd') new_now = timegm(time.localtime()) if new_now - gv.now == 0: # try to avoid drift time.sleep(1)
def GET(self): qdict = web.input() if 'opw' in qdict and qdict['opw'] != "": try: if password_hash(qdict['opw'], gv.sd['salt']) == gv.sd['password']: if qdict['npw'] == "": raise web.seeother('/vo?errorCode=pw_blank') elif qdict['cpw'] != '' and qdict['cpw'] == qdict['npw']: gv.sd['salt'] = password_salt() # Make a new salt gv.sd['password'] = password_hash( qdict['npw'], gv.sd['salt']) else: raise web.seeother('/vo?errorCode=pw_mismatch') else: raise web.seeother('/vo?errorCode=pw_wrong') except KeyError: pass for f in ['name']: if 'o' + f in qdict: gv.sd[f] = qdict['o' + f] for f in ['loc', 'lang']: if 'o' + f in qdict: if f not in gv.sd or gv.sd[f] != qdict['o' + f]: qdict['rstrt'] = '1' # force restart with change gv.sd[f] = qdict['o' + f] if 'onbrd' in qdict: if int(qdict['onbrd']) + 1 != gv.sd['nbrd']: self.update_scount(qdict) gv.sd['nbrd'] = int(qdict['onbrd']) + 1 gv.sd['nst'] = gv.sd['nbrd'] * 8 if 'ohtp' in qdict: if 'htp' not in gv.sd or gv.sd['htp'] != int(qdict['ohtp']): qdict['rbt'] = '1' # force reboot with change in htp gv.sd['htp'] = int(qdict['ohtp']) for f in ['sdt', 'mas', 'mton', 'mtoff', 'wl', 'lr', 'tz']: if 'o' + f in qdict: gv.sd[f] = int(qdict['o' + f]) for f in ['ipas', 'tf', 'urs', 'seq', 'rst', 'lg']: if 'o' + f in qdict and (qdict['o' + f] == 'on' or qdict['o' + f] == '1'): gv.sd[f] = 1 else: gv.sd[f] = 0 jsave(gv.sd, 'sd') report_option_change() if 'rbt' in qdict and qdict['rbt'] == '1': gv.srvals = [0] * (gv.sd['nst']) set_output() report_rebooted() # os.system('reboot') reboot() if 'rstrt' in qdict and qdict['rstrt'] == '1': # restart(2) raise web.seeother('/restart') raise web.seeother('/')
def GET(self): qdict = web.input() if 'opw' in qdict and qdict['opw'] != "": try: if password_hash(qdict['opw'], gv.sd['salt']) == gv.sd['password']: if qdict['npw'] == "": raise web.seeother('/vo?errorCode=pw_blank') elif qdict['cpw'] != '' and qdict['cpw'] == qdict['npw']: gv.sd['salt'] = password_salt() # Make a new salt gv.sd['password'] = password_hash( qdict['npw'], gv.sd['salt']) else: raise web.seeother('/vo?errorCode=pw_mismatch') else: raise web.seeother('/vo?errorCode=pw_wrong') except KeyError: pass try: if 'oipas' in qdict and (qdict['oipas'] == 'on' or qdict['oipas'] == '1'): gv.sd['ipas'] = 1 else: gv.sd['ipas'] = 0 except KeyError: pass if 'oname' in qdict: gv.sd['name'] = qdict['oname'] if 'oloc' in qdict: gv.sd['loc'] = qdict['oloc'] if 'otz' in qdict: gv.sd['tz'] = int(qdict['otz']) try: if 'otf' in qdict and (qdict['otf'] == 'on' or qdict['otf'] == '1'): gv.sd['tf'] = 1 else: gv.sd['tf'] = 0 except KeyError: pass if int(qdict['onbrd']) + 1 != gv.sd['nbrd']: self.update_scount(qdict) gv.sd['nbrd'] = int(qdict['onbrd']) + 1 gv.sd['nst'] = gv.sd['nbrd'] * 8 if 'ohtp' in qdict: gv.sd['htp'] = int(qdict['ohtp']) if 'osdt' in qdict: gv.sd['sdt'] = int(qdict['osdt']) if 'olang' in qdict: gv.sd['lang'] = qdict['olang'] if 'omas' in qdict: gv.sd['mas'] = int(qdict['omas']) if 'omton' in qdict: gv.sd['mton'] = int(qdict['omton']) if 'omtoff' in qdict: gv.sd['mtoff'] = int(qdict['omtoff']) if 'owl' in qdict: gv.sd['wl'] = int(qdict['owl']) if 'ours' in qdict and (qdict['ours'] == 'on' or qdict['ours'] == '1'): gv.sd['urs'] = 1 else: gv.sd['urs'] = 0 if 'oseq' in qdict and (qdict['oseq'] == 'on' or qdict['oseq'] == '1'): gv.sd['seq'] = 1 else: gv.sd['seq'] = 0 if 'orst' in qdict and (qdict['orst'] == 'on' or qdict['orst'] == '1'): gv.sd['rst'] = 1 else: gv.sd['rst'] = 0 if 'olg' in qdict and (qdict['olg'] == 'on' or qdict['olg'] == '1'): gv.sd['lg'] = 1 else: gv.sd['lg'] = 0 if 'olr' in qdict: gv.sd['lr'] = int(qdict['olr']) jsave(gv.sd, 'sd') report_option_change() if 'rbt' in qdict and qdict['rbt'] == '1': gv.srvals = [0] * (gv.sd['nst']) set_output() report_rebooted() # os.system('reboot') reboot() if 'rstrt' in qdict and qdict['rstrt'] == '1': # restart(2) raise web.seeother('/restart') raise web.seeother('/')
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ try: print _('Starting timing loop') + '\n' except Exception: pass last_min = 0 while True: # infinite loop gv.nowt = time.localtime( ) # Current time as time struct. Updated once per second. gv.now = timegm( gv.nowt ) # Current time as timestamp based on local time from the Pi. Updated once per second. if (gv.sd['en'] and not gv.sd['mm'] and (not gv.sd['bsy'] or not gv.sd['seq'])): if gv.now / 60 != last_min: # only check programs once a minute last_min = gv.now / 60 extra_adjustment = plugin_adjustment() for i, p in enumerate(gv.pd): # get both index and prog item # check if program time matches current time, is active, and has a duration if prog_match(p) and p[0] and p[6]: # check each station for boards listed in program up to number of boards in Options for b in range(len(p[7:7 + gv.sd['nbrd']])): for s in range(8): sid = b * 8 + s # station index if gv.sd['mas'] == sid + 1: continue # skip if this is master station if gv.srvals[sid] and gv.sd[ 'seq']: # skip if currently on and sequential mode continue # station duration conditionally scaled by "water level" if gv.sd['iw'][b] & 1 << s: duration_adj = 1.0 if gv.sd['idd'] == 1: duration = p[-1][sid] else: duration = p[6] else: duration_adj = (float(gv.sd['wl']) / 100) * extra_adjustment if gv.sd['idd'] == 1: duration = p[-1][sid] * duration_adj else: duration = p[6] * duration_adj duration = int( round(duration)) # convert to int if p[7 + b] & 1 << s: # if this station is scheduled in this program if gv.sd['seq']: # sequential mode gv.rs[sid][2] = duration gv.rs[sid][ 3] = i + 1 # store program number for scheduling gv.ps[sid][ 0] = i + 1 # store program number for display gv.ps[sid][1] = duration else: # concurrent mode if gv.srvals[ sid]: # if currently on, log result gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) gv.lrun[ 3] = gv.now # think this is unused log_run() report_station_completed(sid + 1) gv.rs[sid][2] = duration gv.rs[sid][ 3] = i + 1 # store program number gv.ps[sid][ 0] = i + 1 # store program number for display gv.ps[sid][1] = duration schedule_stations( p[7:7 + gv.sd['nbrd']]) # turns on gv.sd['bsy'] if gv.sd['bsy']: for b in range(gv.sd['nbrd']): # Check each station once a second for s in range(8): sid = b * 8 + s # station index if gv.srvals[sid]: # if this station is on if gv.now >= gv.rs[sid][1]: # check if time is up gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~(1 << s) if gv.sd['mas'] != sid + 1: # if not master, fill out log gv.ps[sid] = [0, 0] gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) gv.lrun[3] = gv.now log_run() report_station_completed(sid + 1) gv.pon = None # Program has ended gv.rs[sid] = [0, 0, 0, 0] else: # if this station is not yet on if gv.rs[sid][0] <= gv.now < gv.rs[sid][1]: if gv.sd['mas'] != sid + 1: # if not master gv.srvals[sid] = 1 # station is turned on set_output() gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = gv.rs[sid][3] gv.ps[sid][1] = gv.rs[sid][2] if gv.sd['mas'] and gv.sd['mo'][b] & ( 1 << s): # Master settings masid = gv.sd['mas'] - 1 # master index gv.rs[masid][ 0] = gv.rs[sid][0] + gv.sd['mton'] gv.rs[masid][ 1] = gv.rs[sid][1] + gv.sd['mtoff'] gv.rs[masid][3] = gv.rs[sid][3] elif gv.sd['mas'] == sid + 1: gv.sbits[b] |= 1 << sid gv.srvals[masid] = 1 set_output() for s in range(gv.sd['nst']): if gv.rs[s][1]: # if any station is scheduled program_running = True gv.pon = gv.rs[s][3] # Store number of running program break program_running = False gv.pon = None if program_running: if gv.sd['urs'] and gv.sd[ 'rs']: # Stop stations if use rain sensor and rain detected. stop_onrain( ) # Clear schedule for stations that do not ignore rain. for sid in range(len( gv.rs)): # loop through program schedule (gv.ps) if gv.rs[sid][2] == 0: # skip stations with no duration continue if gv.srvals[ sid]: # If station is on, decrement time remaining display if gv.ps[sid][1] > 0: # if time is left gv.ps[sid][1] -= 1 if not program_running: gv.srvals = [0] * (gv.sd['nst']) set_output() gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 if (gv.sd['mas'] # master is defined and (gv.sd['mm'] or not gv.sd['seq'] ) # manual or concurrent mode. ): for b in range(gv.sd['nbrd']): # set stop time for master for s in range(8): sid = b * 8 + s if (gv.sd['mas'] != sid + 1 # if not master and gv.srvals[sid] # station is on and gv.rs[sid][1] >= gv.now # station has a stop time >= now and gv.sd['mo'][b] & (1 << s) # station activates master ): gv.rs[gv.sd['mas'] - 1][1] = gv.rs[sid][1] + gv.sd[ 'mtoff'] # set to future... break # first found will do if gv.sd['urs']: check_rain() # in helpers.py if gv.sd['rd'] and gv.now >= gv.sd[ 'rdst']: # Check if rain delay time is up gv.sd['rd'] = 0 gv.sd['rdst'] = 0 # Rain delay stop time jsave(gv.sd, 'sd') time.sleep(1)
def GET(self): qdict = web.input() if 'opw' in qdict and qdict['opw'] != "": try: if password_hash(qdict['opw'], gv.sd['salt']) == gv.sd['password']: if qdict['npw'] == "": raise web.seeother('/vo?errorCode=pw_blank') elif qdict['cpw'] != '' and qdict['cpw'] == qdict['npw']: gv.sd['salt'] = password_salt() # Make a new salt gv.sd['password'] = password_hash(qdict['npw'], gv.sd['salt']) else: raise web.seeother('/vo?errorCode=pw_mismatch') else: raise web.seeother('/vo?errorCode=pw_wrong') except KeyError: pass for f in ['name']: if 'o'+f in qdict: gv.sd[f] = qdict['o'+f] for f in ['loc', 'lang']: if 'o'+f in qdict: if f not in gv.sd or gv.sd[f] != qdict['o'+f]: qdict['rstrt'] = '1' # force restart with change gv.sd[f] = qdict['o'+f] if 'onbrd' in qdict: if int(qdict['onbrd']) + 1 != gv.sd['nbrd']: self.update_scount(qdict) gv.sd['nbrd'] = int(qdict['onbrd']) + 1 gv.sd['nst'] = gv.sd['nbrd'] * 8 if 'ohtp' in qdict: if 'htp' not in gv.sd or gv.sd['htp'] != int(qdict['ohtp']): qdict['rbt'] = '1' # force reboot with change in htp gv.sd['htp'] = int(qdict['ohtp']) for f in ['sdt', 'mas', 'mton', 'mtoff', 'wl', 'lr', 'tz']: if 'o'+f in qdict: if f == 'mton' and int(qdict['o'+f])<0: #handle values less than zero (temp fix) raise web.seeother('/vo?errorCode=mton_minus') gv.sd[f] = int(qdict['o'+f]) for f in ['ipas', 'tf', 'urs', 'seq', 'rst', 'lg', 'idd', 'pigpio']: if 'o'+f in qdict and (qdict['o'+f] == 'on' or qdict['o'+f] == '1'): gv.sd[f] = 1 else: gv.sd[f] = 0 jsave(gv.sd, 'sd') report_option_change() if 'rbt' in qdict and qdict['rbt'] == '1': gv.srvals = [0] * (gv.sd['nst']) set_output() report_rebooted() # os.system('reboot') reboot() if 'rstrt' in qdict and qdict['rstrt'] == '1': # restart(2) raise web.seeother('/restart') raise web.seeother('/')
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ last_min = 0 zc = 0 supply_temp_readings = [] return_temp_readings = [] # last_mode = gv.sd['mode'] last_mode = 'Invalid Mode' # force intialization last_temp_log = 0 failed_temp_read = 0 last_dewpoint_adjust = 0 # Log the image and all the vsb board fw try: with open('data/version', 'r') as f: image_version = f.read() gv.logger.info('Image version: ' + image_version) except: pass boards = i2c.get_vsb_boards() for board, version in boards.items(): gv.logger.info('VSB Firmware for board: ' + str(board) + ' value: ' + hex(version)) for delay in range(15): time.sleep(1) # wait for ip addressing to settle but keep updating time gv.nowt = time.localtime() # Current time as time struct. Updated once per second. gv.now = timegm(gv.nowt) # Current time as timestamp based on local time from the Pi. Updated once per second. start_time = gv.now check_and_update_upnp() last_upnp_refresh = gv.now # one_way_cooling_adjustments tracks the direction of the last valve change and how many changes we have made # in that direction without going the other direction. This stops us from constantly moving the valve when the # heatpump is off or we cannot achieve our target. one_way_cooling_adjustments = 0 last_ave_supply_temp = None # force everything off set_output() while True: # infinite loop time.sleep(1) gv.nowt = time.localtime() # Current time as time struct. Updated once per second. gv.now = timegm(gv.nowt) # Current time as timestamp based on local time from the Pi. Updated once per second. # perform once per minute processing if gv.now // 60 != last_min: # only check programs once a minute last_min = gv.now // 60 update_radio_present() max_bd = -1 boards = i2c.get_vsb_boards() for bd, version in boards.items(): if bd not in gv.in_bootloader: try: max_bd = max(max_bd, bd) v = i2c_read(i2c.ADDRESS+bd, 0xc) # verify scratch value is as expected. Acts as a touch of the vsb too! if v != bd+16: gv.logger.critical('Main bad scratch value on board: ' + str(bd) + ' value: ' + str(v)) i2c_write(i2c.ADDRESS+bd, 0xc, bd+16) # write scratch register as keepalive except: gv.logger.critical('Cant access scratch register on board: ' + str(bd)) pass # read deadman debug register ignoring all errors. try: v = i2c_read(i2c.ADDRESS+bd, 0xd) if v != 0: gv.logger.critical('Deadman register triggered on board: ' + str(bd) + ' value: ' + str(v)) except: pass cur_bd = (gv.sd['nst']-gv.sd['radiost'])//8 if max_bd+1 > cur_bd: # ensure at nbrd captures all attached VSMs gv.logger.info('Changing nbrd based on attached boards: ' + str(max_bd+1)) adjust_gv_nbrd(max_bd+1) gv.sd['nst'] += 8*(max_bd+1-cur_bd) jsave(gv.sd, 'sd') cur_ip = get_ip() ext_ip_addr = get_external_ip() if gv.sd['master'] and (ext_ip_addr != gv.external_ip or cur_ip != gv.last_ip): gv.external_ip = ext_ip_addr try: # send email if ip addressing changed if gv.sd['teipchange'] and gv.plugin_data['te']['tesender']: subject = "Report from Irricloud" body = 'IP change. Local IP: ' + cur_ip if gv.sd['htp'] != 0 and gv.sd['htp'] != 80: body += ':' + str(gv.sd['htp']) body += ' External IP: ' + ext_ip_addr if gv.sd['external_htp'] != 0: body += ':' + str(gv.sd['external_htp']) gv.plugin_data['te']['tesender'].try_mail(subject, body) except: pass if cur_ip != gv.last_ip: gv.logger.info('IP changed from: ' + gv.last_ip + ' to: ' + cur_ip) gv.last_ip = cur_ip if cur_ip != "No IP Settings": # find router, set up upnp port mapping check_and_update_upnp(cur_ip) last_upnp_refresh = gv.now if gv.sd['upnp_refresh_rate'] > 0 and \ (gv.now-last_upnp_refresh)//60 >= gv.sd['upnp_refresh_rate']: check_and_update_upnp(cur_ip) last_upnp_refresh = gv.now process_actions() last_zc = zc zc = read_sensor_value('zone_call') if zc == None: zc = last_zc log_event('Failed to read zone_call') boiler_md = get_boiler_mode() heatpump_md = get_heatpump_mode() if gv.sd['mode'] != last_mode: # turn everything off log_event('change mode. Turn off boiler, heatpump, circ_pump') if boiler_md != 'none': set_boiler_mode('none') if heatpump_md != 'none': set_heatpump_mode('none') gv.srvals[circ_pump] = 0 set_output() last_zc = 0 # mark as was off last_mode = gv.sd['mode'] remove_action({'what':'set_valve_change'}) if gv.sd['mode'] in ['Heatpump Cooling'] or \ (gv.sd['mode'] in ['Boiler Only'] and not boiler_through_buffer_tank): # use only return water insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':-100}) else: insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':100}) try: temps = read_temps() failed_temp_read = 0 # rather than tracking serial # of thermistors, just assume higher readings are supply # and cooler readings are return (if heating) and vice versa if cooling min_temp = min(temps) max_temp = max(temps) if min_temp < 0 or max_temp < 0: log_event('Bad min/max temps. min: ' + str(min_temp) + ' max: ' + str(max_temp)) if gv.sd['mode'] == 'Heatpump Cooling': supply_temp_readings.append(min_temp) return_temp_readings.append(max_temp) else: supply_temp_readings.append(max_temp) return_temp_readings.append(min_temp) except: if gv.now - start_time > 120: # let things start up before capturing errors failed_temp_read += 1 if failed_temp_read < 300: if failed_temp_read % 10 == 1: # first exception should get cleared by reconnect and is normal log_event('cant read temperatures. Failcount: ' + str(failed_temp_read)) elif failed_temp_read == 300: log_event('TEMPERATURE SENSOR FAILURE') email('Heating', 'TEMPERATURE SENSOR FAILURE') elif failed_temp_read % 300 == 0: log_event('Ongoing temp failure. Failcount: ' + str(failed_temp_read)) if len(supply_temp_readings) > 5: supply_temp_readings.pop(0) if len(return_temp_readings) > 5: return_temp_readings.pop(0) try: ave_supply_temp = sum(supply_temp_readings)/float(len(supply_temp_readings)) if ave_supply_temp < 0: log_event('Bad ave_supply_temp: ' + str(ave_supply_temp)) except ZeroDivisionError: ave_supply_temp = -1 try: ave_return_temp = sum(return_temp_readings)/float(len(return_temp_readings)) if ave_return_temp < 0: log_event('Bad ave_return_temp: ' + str(ave_return_temp)) except ZeroDivisionError: ave_return_temp = -1 if gv.now - last_temp_log >= 600: last_temp_log = gv.now ast_c = ave_supply_temp ast_f = ast_c*1.8 + 32 art_c = ave_return_temp art_f = art_c*1.8 + 32 dew_f = dew*1.8 + 32 log_event('supply temp: ' + "{0:.2f}".format(ast_c) + 'C ' + "{0:.2f}".format(ast_f) + 'F' + '; ' + \ 'return temp: ' + "{0:.2f}".format(art_c) + 'C ' + "{0:.2f}".format(art_f) + 'F' + '; ' + \ 'dewpoint: ' + "{0:.2f}".format(dew) + 'C ' + "{0:.2f}".format(dew_f) + 'F') if zc != last_zc: # change in zone call if gv.sd['mode'] == 'None': zc = last_zc # dont do anything in terms of moving water elif last_zc == 0: # was off, now on? supply_temp_readings = [] return_temp_readings = [] last_ave_supply_temp = None log_event('zone call on; enable circ pump') gv.srvals[circ_pump] = 1 set_output() # for cooling or boiler operation start with only return water. For heating, only buffer tank water if gv.sd['mode'] in ['Heatpump Cooling']: remove_action({'what':'set_valve_change'}) insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':-100}) one_way_cooling_adjustments = 0 elif not boiler_through_buffer_tank: remove_action({'what':'set_valve_change'}) if gv.sd['mode'] in ['Boiler Only']: insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':-100}) else: insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':100}) if gv.sd['mode'] in ['Boiler Only', 'Boiler and Heatpump']: log_event('zone call on; enable boiler') set_boiler_mode('heating') else: # was on, now off msg_start = 'zone call off; ' gv.srvals[circ_pump] = 0 set_output() if boiler_md == 'heating' and \ gv.sd['mode'] in ['Boiler Only', 'Boiler and Heatpump', 'Heatpump then Boiler']: msg_start += 'disable boiler; ' set_boiler_mode('none') if heatpump_md == 'heating' and \ gv.sd['mode'] in ['Boiler and Heatpump', 'Heatpump then Boiler', 'Heatpump Only']: msg_start += 'disable heatpump; ' set_heatpump_mode('none') if heatpump_md == 'cooling' and gv.sd['mode'] == 'Heatpump Cooling': msg_start += 'disable heatpump; ' set_heatpump_mode('none') log_event(msg_start + 'supply: ' + "{0:.2f}".format(ave_supply_temp) + ' return: ' + "{0:.2f}".format(ave_return_temp)) elif zc == 1: # still on? if len(supply_temp_readings) < 5 or len(return_temp_readings) < 5: continue if gv.sd['mode'] in ['Heatpump Only', 'Boiler and Heatpump', 'Heatpump then Boiler']: if ave_supply_temp < heatpump_setpoint_h-5: if heatpump_md == 'none' and gv.now-last_heatpump_off > 3*60: # log_event('reenable heatpump; supply: ' + str(ave_supply_temp)) set_heatpump_mode('heating') if ave_supply_temp > heatpump_setpoint_h-2: if heatpump_md == 'heating' and gv.now-last_heatpump_on > 3*60: # log_event('disable heatpump; supply: ' + str(ave_supply_temp)) set_heatpump_mode('none') if gv.sd['mode'] == 'Heatpump then Boiler': if ave_supply_temp < heatpump_setpoint_h-13 or ave_return_temp < 33: if boiler_md == 'none' and gv.now-last_boiler_off > 2*60 and \ gv.now-last_heatpump_on > 3*60: log_event('reenable boiler; supply: ' + "{0:.2f}".format(ave_supply_temp) + ' return: ' + "{0:.2f}".format(ave_return_temp)) # Use only boiler for a while if not boiler_through_buffer_tank: remove_action({'what':'set_valve_change'}) insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':-100}) set_heatpump_mode('none') set_boiler_mode('heating') insert_action(gv.now+45*60, {'what':'set_boiler_mode', 'mode':'none'}) if gv.sd['mode'] == 'Heatpump Cooling' and gv.now-last_dewpoint_adjust >= 60: dewpoint_margin = 1.5 target = max(dew+dewpoint_margin+1, 10.) adjust = 0 if ave_supply_temp <= dew+dewpoint_margin and one_way_cooling_adjustments > min_cooling_adjustments: remove_action({'what':'set_valve_change'}) insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':-100}) msg = 'Close valve; avoid condensation' log_event(msg + ': ' + "{0:.2f}".format(dew) + 'C target: ' + "{0:.2f}".format(target) + 'C supply: ' + "{0:.2f}".format(ave_supply_temp) + 'C') last_dewpoint_adjust = gv.now last_ave_supply_temp = None one_way_cooling_adjustments = min_cooling_adjustments elif target < ave_supply_temp - .1: remove_action({'what':'set_valve_change'}) adjust = 0 if one_way_cooling_adjustments < 0: one_way_cooling_adjustments = 0 adjust += 2 adjust += cooling_adjust_per_degree * (ave_supply_temp - target) if last_ave_supply_temp != None and last_ave_supply_temp - ave_supply_temp > 0 and \ gv.now-last_dewpoint_adjust <= 180: # already going down? Be patient new_adjust = adjust - 2*cooling_adjust_per_degree * (last_ave_supply_temp - ave_supply_temp) msg = 'already going down' gv.logger.debug(msg + ': ' + \ ' adjust: ' + "{0:.2f}".format(adjust) + \ ' new_adjust: ' + "{0:.2f}".format(new_adjust)) adjust = max(0, new_adjust) adjust = int(round(adjust)) msg = 'Ignoring request for more buffer tank water' if adjust > 0 and one_way_cooling_adjustments < max_cooling_adjustments: insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':adjust}) last_dewpoint_adjust = gv.now last_ave_supply_temp = ave_supply_temp msg = 'More buffer tank water' elif target > ave_supply_temp + .1: remove_action({'what':'set_valve_change'}) adjust = 0 if one_way_cooling_adjustments > 0: one_way_cooling_adjustments = 0 adjust -= 2 adjust += cooling_adjust_per_degree * (ave_supply_temp - target) if last_ave_supply_temp != None and last_ave_supply_temp - ave_supply_temp < 0 and \ gv.now-last_dewpoint_adjust <= 180: # already going up? Be patient new_adjust = adjust - 2*cooling_adjust_per_degree * (last_ave_supply_temp - ave_supply_temp) msg = 'already going up' gv.logger.debug(msg + ': ' + \ ' adjust: ' + "{0:.2f}".format(adjust) + \ ' new_adjust: ' + "{0:.2f}".format(new_adjust)) adjust = min(0, new_adjust) adjust = int(round(adjust)) msg = 'Ignoring request for more return water' if adjust < 0 and one_way_cooling_adjustments > min_cooling_adjustments: insert_action(gv.now, {'what':'set_valve_change', 'valve_change_percent':adjust}) last_dewpoint_adjust = gv.now last_ave_supply_temp = ave_supply_temp msg = 'More return water' else: msg = 'Not changing valve' gv.logger.debug(msg + ': ' + str(one_way_cooling_adjustments) + \ ' dew: ' + "{0:.2f}".format(dew) + 'C' + \ ' target: ' + "{0:.2f}".format(target) + 'C' + \ ' supply: ' + "{0:.2f}".format(ave_supply_temp) + 'C') if (adjust > 0 and one_way_cooling_adjustments < max_cooling_adjustments) or \ (adjust < 0 and one_way_cooling_adjustments > min_cooling_adjustments): one_way_cooling_adjustments += adjust
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ try: print(_(u"Starting timing loop") + u"\n") except Exception: pass last_min = 0 while True: # infinite loop cur_ord = ( date.today().toordinal() ) # day of year if cur_ord > gv.day_ord: gv.day_ord = cur_ord report_new_day() gv.nowt = ( time.localtime() ) # Current time as time struct. Updated once per second. gv.now = timegm( gv.nowt ) # Current time as timestamp based on local time from the Pi. Updated once per second. if ( gv.sd[u"en"] and not gv.sd[u"mm"] and (not gv.sd[u"bsy"] or not gv.sd[u"seq"]) ): if int(gv.now // 60) != last_min: # only check programs once a minute last_min = int(gv.now // 60) extra_adjustment = plugin_adjustment() for i, p in enumerate(gv.pd): # get both index and prog item if prog_match(p) and any(p[u"duration_sec"]): # check each station per boards listed in program up to number of boards in Options for b in range(len(p[u"station_mask"])): for s in range(8): sid = b * 8 + s # station index if gv.sd[u"mas"] == sid + 1: continue # skip, this is master station if ( gv.srvals[sid] and gv.sd[u"seq"] ): # skip if currently on and sequential mode continue # station duration conditionally scaled by "water level" if gv.sd[u"iw"][b] & 1 << s: duration_adj = 1.0 if gv.sd[u"idd"]: duration = p[u"duration_sec"][sid] else: duration = p[u"duration_sec"][0] else: duration_adj = ( gv.sd[u"wl"] / 100.0 ) * extra_adjustment if gv.sd[u"idd"]: duration = ( p[u"duration_sec"][sid] * duration_adj ) else: duration = p[u"duration_sec"][0] * duration_adj duration = int(round(duration)) # convert to int if ( p[u"station_mask"][b] & 1 << s ): # if this station is scheduled in this program gv.rs[sid][2] = duration gv.rs[sid][3] = i + 1 # program number for scheduling gv.ps[sid][0] = i + 1 # program number for display gv.ps[sid][1] = duration schedule_stations(p[u"station_mask"]) # turns on gv.sd["bsy"] if gv.sd[u"bsy"]: for b in range(gv.sd[u"nbrd"]): # Check each station once a second for s in range(8): sid = b * 8 + s # station index if gv.srvals[sid]: # if this station is on if gv.now >= gv.rs[sid][1]: # check if time is up gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~(1 << s) if gv.sd[u"mas"] != sid + 1: # if not master, fill out log gv.ps[sid] = [0, 0] gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) print(u"logging @ time check") log_run() report_station_completed(sid + 1) gv.pon = None # Program has ended gv.rs[sid] = [0, 0, 0, 0] else: # if this station is not yet on if gv.rs[sid][0] <= gv.now < gv.rs[sid][1]: if gv.sd[u"mas"] != sid + 1: # if not master gv.srvals[sid] = 1 # station is turned on set_output() gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = gv.rs[sid][3] gv.ps[sid][1] = gv.rs[sid][2] if gv.sd[u"mas"] and gv.sd[u"mo"][b] & ( 1 << s ): # Master settings masid = gv.sd[u"mas"] - 1 # master index gv.rs[masid][0] = gv.rs[sid][0] + gv.sd[u"mton"] gv.rs[masid][1] = gv.rs[sid][1] + gv.sd[u"mtoff"] gv.rs[masid][3] = gv.rs[sid][3] elif gv.sd[u"mas"] == sid + 1: # if this is master masid = gv.sd[u"mas"] - 1 # master index gv.sbits[b] |= 1 << sid gv.srvals[masid] = 1 set_output() for s in range(gv.sd[u"nst"]): if gv.rs[s][1]: # if any station is scheduled program_running = True gv.pon = gv.rs[s][3] # Store number of running program break program_running = False gv.pon = None if program_running: if ( gv.sd[u"urs"] and gv.sd[u"rs"] ): # Stop stations if use rain sensor and rain detected. stop_onrain() # Clear schedule for stations that do not ignore rain. for sid in range(len(gv.rs)): # loop through program schedule (gv.ps) if gv.rs[sid][2] == 0: # skip stations with no duration continue if gv.srvals[ sid ]: # If station is on, decrement time remaining display if gv.ps[sid][1] > 0: # if time is left gv.ps[sid][1] -= 1 if not program_running: gv.srvals = [0] * (gv.sd[u"nst"]) set_output() gv.sbits = [0] * (gv.sd[u"nbrd"] + 1) gv.ps = [] for i in range(gv.sd[u"nst"]): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd[u"nst"]): gv.rs.append([0, 0, 0, 0]) gv.sd[u"bsy"] = 0 if gv.sd[u"mas"] and ( # master is defined gv.sd[u"mm"] or not gv.sd[u"seq"] ): # manual or concurrent mode. for b in range(gv.sd[u"nbrd"]): # set stop time for master for s in range(8): sid = b * 8 + s if ( gv.sd[u"mas"] != sid + 1 # if not master and gv.srvals[sid] # station is on and gv.rs[sid][1] >= gv.now # station has a stop time >= now and gv.sd[u"mo"][b] & (1 << s) # station activates master ): gv.rs[gv.sd[u"mas"] - 1][1] = ( gv.rs[sid][1] + gv.sd[u"mtoff"] ) # set to future... break # first found will do if gv.sd[u"urs"]: check_rain() # in helpers.py if gv.sd[u"rd"] and gv.now >= gv.sd[u"rdst"]: # Check if rain delay time is up gv.sd[u"rd"] = 0 gv.sd[u"rdst"] = 0 # Rain delay stop time jsave(gv.sd, u"sd") time.sleep(1)
gv.plugin_menu.sort(key=lambda entry: entry[0]) # Keep plugin manager at top of menu try: for i, item in enumerate(gv.plugin_menu): if u"/plugins" in item: gv.plugin_menu.pop(i) except Exception as e: print(u"Creating plugins menu", e) pass tl = Thread(target=timing_loop) tl.daemon = True tl.start() if gv.use_gpio_pins: set_output() app.notfound = lambda: web.seeother(u"/") ########################### #### For HTTPS (SSL): #### if gv.sd["htp"] == 443: try: from cheroot.server import HTTPServer from cheroot.ssl.builtin import BuiltinSSLAdapter HTTPServer.ssl_adapter = BuiltinSSLAdapter( certificate='/usr/lib/ssl/certs/SIP.crt', private_key='/usr/lib/ssl/private/SIP.key' ) except IOError as e:
def GET(self): qdict = web.input() if 'opw' in qdict and qdict['opw'] != "": try: if password_hash(qdict['opw'], gv.sd['salt']) == gv.sd['password']: if qdict['npw'] == "": raise web.seeother('/vo?errorCode=pw_blank') elif qdict['cpw'] != '' and qdict['cpw'] == qdict['npw']: gv.sd['salt'] = password_salt() # Make a new salt gv.sd['password'] = password_hash(qdict['npw'], gv.sd['salt']) else: raise web.seeother('/vo?errorCode=pw_mismatch') else: raise web.seeother('/vo?errorCode=pw_wrong') except KeyError: pass try: if 'oipas' in qdict and (qdict['oipas'] == 'on' or qdict['oipas'] == '1'): gv.sd['ipas'] = 1 else: gv.sd['ipas'] = 0 except KeyError: pass if 'oname' in qdict: gv.sd['name'] = qdict['oname'] if 'oloc' in qdict: gv.sd['loc'] = qdict['oloc'] if 'otz' in qdict: gv.sd['tz'] = int(qdict['otz']) try: if 'otf' in qdict and (qdict['otf'] == 'on' or qdict['otf'] == '1'): gv.sd['tf'] = 1 else: gv.sd['tf'] = 0 except KeyError: pass if int(qdict['onbrd']) + 1 != gv.sd['nbrd']: self.update_scount(qdict) gv.sd['nbrd'] = int(qdict['onbrd']) + 1 gv.sd['nst'] = gv.sd['nbrd'] * 8 if 'ohtp' in qdict: gv.sd['htp'] = int(qdict['ohtp']) if 'osdt' in qdict: gv.sd['sdt'] = int(qdict['osdt']) if 'olang' in qdict: gv.sd['lang'] = qdict['olang'] if 'omas' in qdict: gv.sd['mas'] = int(qdict['omas']) if 'omton' in qdict: gv.sd['mton'] = int(qdict['omton']) if 'omtoff' in qdict: gv.sd['mtoff'] = int(qdict['omtoff']) if 'owl' in qdict: gv.sd['wl'] = int(qdict['owl']) if 'ours' in qdict and (qdict['ours'] == 'on' or qdict['ours'] == '1'): gv.sd['urs'] = 1 else: gv.sd['urs'] = 0 if 'oseq' in qdict and (qdict['oseq'] == 'on' or qdict['oseq'] == '1'): gv.sd['seq'] = 1 else: gv.sd['seq'] = 0 if 'orst' in qdict and (qdict['orst'] == 'on' or qdict['orst'] == '1'): gv.sd['rst'] = 1 else: gv.sd['rst'] = 0 if 'olg' in qdict and (qdict['olg'] == 'on' or qdict['olg'] == '1'): gv.sd['lg'] = 1 else: gv.sd['lg'] = 0 if 'olr' in qdict: gv.sd['lr'] = int(qdict['olr']) jsave(gv.sd, 'sd') report_option_change() if 'rbt' in qdict and qdict['rbt'] == '1': gv.srvals = [0] * (gv.sd['nst']) set_output() report_rebooted() # os.system('reboot') reboot() if 'rstrt' in qdict and qdict['rstrt'] == '1': # restart(2) raise web.seeother('/restart') raise web.seeother('/')
def timing_loop(): """ ***** Main timing algorithm. Runs in a separate thread.***** """ try: print _('Starting timing loop') + '\n' except Exception: pass last_min = 0 while True: # infinite loop gv.now = timegm( time.localtime() ) # Current time as timestamp based on local time from the Pi. updated once per second. if gv.sd['en'] and not gv.sd['mm'] and (not gv.sd['bsy'] or not gv.sd['seq']): if gv.now / 60 != last_min: # only check programs once a minute last_min = gv.now / 60 extra_adjustment = plugin_adjustment() for i, p in enumerate(gv.pd): # get both index and prog item # check if program time matches current time, is active, and has a duration if prog_match(p) and p[0] and p[6]: duration = p[6] * gv.sd[ 'wl'] / 100 * extra_adjustment # program duration scaled by "water level" # check each station for boards listed in program up to number of boards in Options for b in range(len(p[7:7 + gv.sd['nbrd']])): for s in range(8): sid = b * 8 + s # station index if sid + 1 == gv.sd['mas']: continue # skip if this is master station if gv.srvals[sid]: # skip if currently on continue if p[7 + b] & 1 << s: # if this station is scheduled in this program if gv.sd['seq']: # sequential mode gv.rs[sid][2] = duration gv.rs[sid][ 3] = i + 1 # store program number for scheduling gv.ps[sid][ 0] = i + 1 # store program number for display gv.ps[sid][1] = duration else: # concurrent mode # If duration is shortter than any already set for this station if duration < gv.rs[sid][2]: continue else: gv.rs[sid][2] = duration gv.rs[sid][ 3] = i + 1 # store program number gv.ps[sid][ 0] = i + 1 # store program number for display gv.ps[sid][1] = duration schedule_stations( p[7:7 + gv.sd['nbrd']]) # turns on gv.sd['bsy'] if gv.sd['bsy']: for b in range(gv.sd['nbrd']): # Check each station once a second for s in range(8): sid = b * 8 + s # station index if gv.srvals[sid]: # if this station is on if gv.now >= gv.rs[sid][1]: # check if time is up gv.srvals[sid] = 0 set_output() gv.sbits[b] &= ~(1 << s) if gv.sd['mas'] - 1 != sid: # if not master, fill out log gv.ps[sid] = [0, 0] gv.lrun[0] = sid gv.lrun[1] = gv.rs[sid][3] gv.lrun[2] = int(gv.now - gv.rs[sid][0]) gv.lrun[3] = gv.now log_run() gv.pon = None # Program has ended gv.rs[sid] = [0, 0, 0, 0] else: # if this station is not yet on if gv.rs[sid][0] <= gv.now < gv.rs[sid][1]: if gv.sd['mas'] - 1 != sid: # if not master gv.srvals[sid] = 1 # station is turned on set_output() gv.sbits[b] |= 1 << s # Set display to on gv.ps[sid][0] = gv.rs[sid][3] gv.ps[sid][1] = gv.rs[sid][2] if gv.sd['mas'] and gv.sd['mo'][b] & 1 << ( s - (s / 8) * 80): # Master settings masid = gv.sd['mas'] - 1 # master index gv.rs[masid][ 0] = gv.rs[sid][0] + gv.sd['mton'] gv.rs[masid][ 1] = gv.rs[sid][1] + gv.sd['mtoff'] gv.rs[masid][3] = gv.rs[sid][3] elif gv.sd['mas'] == sid + 1: gv.sbits[b] |= 1 << sid # (gv.sd['mas'] - 1) gv.srvals[masid] = 1 set_output() for s in range(gv.sd['nst']): if gv.rs[s][1]: # if any station is scheduled program_running = True gv.pon = gv.rs[s][3] # Store number of running program break program_running = False gv.pon = None if program_running: if gv.sd['urs'] and gv.sd[ 'rs']: # Stop stations if use rain sensor and rain detected. stop_onrain( ) # Clear schedule for stations that do not ignore rain. for idx in range(len( gv.rs)): # loop through program schedule (gv.ps) if gv.rs[idx][2] == 0: # skip stations with no duration continue if gv.srvals[ idx]: # If station is on, decrement time remaining display gv.ps[idx][1] -= 1 if not program_running: gv.srvals = [0] * (gv.sd['nst']) set_output() gv.sbits = [0] * (gv.sd['nbrd'] + 1) gv.ps = [] for i in range(gv.sd['nst']): gv.ps.append([0, 0]) gv.rs = [] for i in range(gv.sd['nst']): gv.rs.append([0, 0, 0, 0]) gv.sd['bsy'] = 0 if gv.sd['mas'] and ( gv.sd['mm'] or not gv.sd['seq'] ): # handle master for maual or concurrent mode. mval = 0 for sid in range(gv.sd['nst']): bid = sid / 8 s = sid - bid * 8 if gv.sd['mas'] != sid + 1 and (gv.srvals[sid] and gv.sd['mo'][bid] & 1 << s): mval = 1 break if not mval: gv.rs[gv.sd['mas'] - 1][1] = gv.now # turn off master if gv.sd['urs']: check_rain() # in helpers.py if gv.sd['rd'] and gv.now >= gv.sd[ 'rdst']: # Check of rain delay time is up gv.sd['rd'] = 0 gv.sd['rdst'] = 0 # Rain delay stop time jsave(gv.sd, 'sd') time.sleep(1)