mirror of https://github.com/noisymime/OSPi.git
Merged options into Dan-in-CA latest version
Improved options handling code: simplified passing of options, factored out option UI details into data file, added new options for name and station name length, and brought logging options into the main options page. Fixed some IE rendering issues and made tooltips a full toggle as well.
This commit is contained in:
parent
eb47890e1d
commit
be16ebe3e3
17
README.md
17
README.md
|
@ -12,6 +12,23 @@ UPDATES
|
|||
===========
|
||||
***********
|
||||
|
||||
September 28 2013 (jonathanmarsh)
|
||||
--------------
|
||||
Additions, bug fixes:<br/>
|
||||
1. Improved options handling and passing logic
|
||||
2. Added a "System Name" option to help users distinguish between multiple systems
|
||||
3. Configurable station name length (increased default to 32)
|
||||
4. Added logging options to options page
|
||||
|
||||
September 23 2013
|
||||
--------------
|
||||
Additions, bug fixes:<br/>
|
||||
1. Added a new revisions page to the native web interface.
|
||||
2. Modified the home.js file to show time zone info in the last run log near the bottom of the page.
|
||||
3. Fixed a bug in concurrent mode that kept a station running after it's duration had expired.
|
||||
4. Fixed a bug that would cause an exception (freeze the program) after the number of expansion boards was changed in Options.
|
||||
5. Fixed a bug that would stop a running station and clear scheduled stations when the number of expansion boards was changed in Options.
|
||||
|
||||
September 10 2013
|
||||
--------------
|
||||
Additions, bug fixes:<br/>
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
<meta name=viewport content="width=640">
|
||||
<meta name=viewport content="width=640">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon"/>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
var opts=[
|
||||
["System name","string","name","Unique name of this OpenSprinkler system."],
|
||||
["HTTP port","int","htp", "HTTP port (effective after reboot)."],
|
||||
["Location","string","loc", "City name or zip code. Use comma or + in place of space."],
|
||||
["Time zone","int","tz", "Example: GMT-4:00, GMT+5:30 (effective after reboot)."],
|
||||
["Sequential","boolean","seq", "Sequential or concurrent running mode"],
|
||||
["Extension boards","int","nbrd", "Number of extension boards"],
|
||||
["Station delay","int","sdt", "Station delay time (in seconds), between 0 and 240."],
|
||||
["Master station","int","mas", "Select master station"],
|
||||
["Master on adjust","int","mton", "Master on delay (in seconds), between +0 and +60."],
|
||||
["Master off adjust","int","mtoff", "Master off delay (in seconds), between -60 and +60."],
|
||||
["Use rain sensor","boolean","urs", "Use rain sensor"],
|
||||
["Normally open","boolean","rst", "Rain sensor type"],
|
||||
["Water level (%)","int","wl", "Water level, between 0% and 250%."],
|
||||
["Enable logging","boolean","lg", "Log all events - note that repetitive writing to an SD card can shorten its lifespan."],
|
||||
["Maximum log entries","int","lr", "Length of log to keep, 0=no limits."],
|
||||
["Ignore password","boolean","ipas", "Ignore web password"]
|
||||
];
|
349
ospi.py
349
ospi.py
|
@ -1,9 +1,13 @@
|
|||
#!/usr/bin/python
|
||||
"""Updated 10/September/2013."""
|
||||
"""Updated 19/September/2013."""
|
||||
import re, os, json, time, base64, thread # standard Python modules
|
||||
import web # the Web.py module. See webpy.org (Enables the OpenSprinkler web interface)
|
||||
import gv # 'global vars' An empty module, used for storing vars (as attributes), that need to be 'global' across threads and between functions and classes.
|
||||
import RPi.GPIO as GPIO # Required for accessing General Purpose Input Output pins on Raspberry Pi
|
||||
#### Revision information ####
|
||||
gv.ver = 183
|
||||
gv.rev = 135
|
||||
gv.rev_date = '23/September/2013'
|
||||
|
||||
#### urls is a feature of web.py. When a GET request is recieved , the corrisponding class is exicuted.
|
||||
urls = [
|
||||
|
@ -27,6 +31,7 @@ urls = [
|
|||
'/lo', 'log_options',
|
||||
'/rp', 'run_now',
|
||||
'/ttu', 'toggle_temp',
|
||||
'/rev', 'show_revision',
|
||||
]
|
||||
|
||||
#### Import ospi_addon module (ospi_addon.py) if it exists. ####
|
||||
|
@ -121,7 +126,7 @@ def prog_match(prog):
|
|||
return 1 # Program matched
|
||||
return 0
|
||||
|
||||
def schedule_stations():
|
||||
def schedule_stations(stations):
|
||||
"""Schedule stattions/valves/zones to run."""
|
||||
if gv.sd['rd'] or (gv.sd['urs'] and gv.sd['rs']): # If rain delay or rain detected by sensor
|
||||
rain = True
|
||||
|
@ -129,7 +134,7 @@ def schedule_stations():
|
|||
rain = False
|
||||
accumulate_time = gv.now
|
||||
if gv.sd['seq']: #sequential mode, stations run one after another
|
||||
for b in range(gv.sd['nbrd']):
|
||||
for b in range(len(stations)):
|
||||
for s in range(8):
|
||||
sid = b*8 + s # station index
|
||||
if gv.rs[sid][2]: # if station has a duration value
|
||||
|
@ -139,20 +144,22 @@ def schedule_stations():
|
|||
gv.rs[sid][1] = accumulate_time # set new stop time
|
||||
accumulate_time += gv.sd['sdt'] # add station delay
|
||||
else:
|
||||
gv.sbits[b] = gv.sbits[b]&~2**s
|
||||
gv.sbits[b] = gv.sbits[b]&~1<<s
|
||||
gv.ps[s] = [0,0]
|
||||
|
||||
else: # concurrent mode, stations allowed to run in parallel
|
||||
for b in range(gv.sd['nbrd']):
|
||||
for b in range(len(stations)):
|
||||
for s in range(8):
|
||||
sid = b*8 + s # station index
|
||||
if not stations[b]&1<<s: # skip stations not in prog
|
||||
continue
|
||||
if gv.rs[sid][2]: # if station has a duration value
|
||||
if not rain or gv.sd['ir'][b]&1<<s: # if no rain or station ignores rain
|
||||
gv.rs[sid][0] = accumulate_time # set start time
|
||||
gv.rs[sid][1] = accumulate_time + gv.rs[sid][2] # Stop time = Start time + duration
|
||||
gv.rs[sid][0] = gv.now #accumulate_time # set start time
|
||||
gv.rs[sid][1] = (gv.now + gv.rs[sid][2]) # set stop time
|
||||
else: # if rain and station does not ignore, clear station from display
|
||||
gv.sbits[b] = gv.sbits[b]&~2**s
|
||||
gv.ps[s] = [0,0]
|
||||
gv.ps[s] = [0,0]
|
||||
gv.sd['bsy'] = 1
|
||||
return
|
||||
|
||||
|
@ -188,7 +195,6 @@ def main_loop(): # Runs in a seperate thread
|
|||
print 'Starting main loop \n'
|
||||
last_min = 0
|
||||
while True: # infinite loop
|
||||
match = 0
|
||||
gv.now = time.time()+((gv.sd['tz']/4)-12)*3600 # Current time based on UTC time from the Pi adjusted by the Time Zone setting from options. updated once per second.
|
||||
if gv.sd['en'] and not gv.sd['mm'] and (not gv.sd['bsy'] or not gv.sd['seq']): # and not gv.sd['rd']:
|
||||
lt = time.gmtime(gv.now)
|
||||
|
@ -196,31 +202,40 @@ def main_loop(): # Runs in a seperate thread
|
|||
last_min = (lt[3]*60)+lt[4]
|
||||
for i, p in enumerate(gv.pd): # get both index and prog item
|
||||
if prog_match(p) and p[0] and p[6]: # check if program time matches current time, is active, and has a duration
|
||||
for b in range(gv.sd['nbrd']): # check each station
|
||||
duration = p[6]*gv.sd['wl']/100 # program duration scaled by "water level"
|
||||
for b in range(len(p[7:7+gv.sd['nbrd']])): # check each station for boards listed in program up to number of boards in Options
|
||||
for s in range(8):
|
||||
sid = b*8+s # station index
|
||||
if sid+1 == gv.sd['mas']: continue # skip if this is master valve
|
||||
if sid+1 == gv.sd['mas']: continue # skip if this is master station
|
||||
if gv.srvals[sid]: continue # skip if currently on
|
||||
|
||||
if p[7+b]&1<<s: # if this station is scheduled in this program
|
||||
gv.rs[sid][2] = p[6]*gv.sd['wl']/100 # duration scaled by water level
|
||||
gv.rs[sid][3] = i+1 # store program number
|
||||
gv.ps[sid][0] = i+1 # store program number for display
|
||||
gv.ps[sid][1] = gv.rs[sid][2] # duration
|
||||
match = True
|
||||
if match:
|
||||
schedule_stations() # turns on gv.sd['bsy']
|
||||
if gv.sd['seq']: # sequential mode
|
||||
gv.rs[sid][2] = duration # p[6]*gv.sd['wl']/100 # store duration scaled by water level
|
||||
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 < gv.rs[sid][2]: # If duration is shortter than any already set for this station
|
||||
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']):
|
||||
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] = gv.sbits[b]&~2**s
|
||||
if gv.sd['mas']-1 != sid: # if not master, fill out log
|
||||
gv.sbits[b] = gv.sbits[b]&~2**s
|
||||
gv.ps[sid] = [0,0]
|
||||
gv.lrun[0] = sid
|
||||
gv.lrun[1] = gv.rs[sid][3]
|
||||
|
@ -228,29 +243,28 @@ def main_loop(): # Runs in a seperate thread
|
|||
gv.lrun[3] = gv.now
|
||||
log_run()
|
||||
gv.pon = None # Program has ended
|
||||
elif gv.sd['mas']-1 == sid:
|
||||
gv.sbits[b] = gv.sbits[b]&~2**s
|
||||
gv.rs[sid] = [0,0,0,0]
|
||||
else: # if this station is not yet on
|
||||
if gv.now >= gv.rs[sid][0] and 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] = gv.sbits[b]|2**s # Set display to on
|
||||
gv.sbits[b] = 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]
|
||||
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] = gv.sbits[b]|2**sid #(gv.sd['mas'] - 1)
|
||||
gv.sbits[b] = 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 running
|
||||
if gv.rs[s][1]: # if any station is scheduled
|
||||
#if gv.srvals[s]: # if any station is on
|
||||
program_running = True
|
||||
gv.pon = gv.rs[s][3] # Store number of running program
|
||||
break
|
||||
|
@ -260,13 +274,11 @@ def main_loop(): # Runs in a seperate thread
|
|||
if program_running:
|
||||
if gv.sd['urs'] and gv.sd['rs']: # Stop stations if use rain sensor and rain detected.
|
||||
stop_onrain() #### Should clear schedule for stations that do not ignore rain ####
|
||||
for idx in range(len(gv.ps)): # loop through program schedule (gv.ps)
|
||||
if gv.ps[idx][1] == 0: # skip stations with no duration
|
||||
for idx in range(len(gv.rs)): # loop through program schedule (gv.ps) #### MAYBE SB gv.rs
|
||||
if gv.rs[idx][2] == 0: # skip stations with no duration
|
||||
continue
|
||||
if gv.srvals[idx]: # If station is on, decrement time remaining
|
||||
if gv.srvals[idx]: # If station is on, decrement time remaining display
|
||||
gv.ps[idx][1] -= 1
|
||||
if gv.ps[idx][1] == 0:
|
||||
gv.ps[idx][0] = 0
|
||||
|
||||
if not program_running:
|
||||
gv.srvals = [0]*(gv.sd['nst'])
|
||||
|
@ -379,6 +391,7 @@ def to_sec(d=0, h=0, m=0, s=0):
|
|||
|
||||
|
||||
#### Global vars #####
|
||||
|
||||
try:
|
||||
sdf = open('./data/sd.json', 'r') ## A config file ##
|
||||
gv.sd = json.load(sdf) #Settings Dictionary. A set of vars kept in memory and persisted in a file
|
||||
|
@ -393,13 +406,17 @@ try:
|
|||
if not 'lr' in gv.sd: gv.sd['lr'] = 100
|
||||
if not 'seq' in gv.sd: gv.sd['seq'] = 1
|
||||
if not 'tu' in gv.sd: gv.sd['tu'] = "C"
|
||||
if not 'ir' in gv.sd: gv.sd['ir'] = [0]
|
||||
if not 'ir' in gv.sd: gv.sd['ir'] = [0]#*gv.sd['nbrd']
|
||||
if not 'loc' in gv.sd: gv.sd['loc'] = ""
|
||||
if not 'snlen' in gv.sd: gv.sd['snlen'] = 32
|
||||
if not 'name' in gv.sd: gv.sd['name'] = "OpenSprinkler Pi"
|
||||
except IOError: # If file does not exist, create with defaults.
|
||||
gv.sd = ({"en": 1, "seq": 1, "mnp": 32, "ir": [0], "rsn": 0, "htp": 8080, "nst": 8,
|
||||
"rdst": 0, "loc": "", "tz": 48, "rs": 0, "rd": 0, "mton": 0,
|
||||
"lr": "100", "sdt": 0, "mas": 0, "wl": 100, "bsy": 0, "lg": "",
|
||||
"urs": 0, "nopts": 13, "pwd": "b3BlbmRvb3I=", "ipas": 0, "rst": 1,
|
||||
"mm": 0, "mo": [0], "rbt": 0, "mtoff": 0, "nprogs": 1, "nbrd": 1, "tu": "C"})
|
||||
"mm": 0, "mo": [0], "rbt": 0, "mtoff": 0, "nprogs": 1, "nbrd": 1, "tu": "C",
|
||||
"snlen":32, "name":"OpenSprinkler Pi"})
|
||||
sdf = open('./data/sd.json', 'w')
|
||||
json.dump(gv.sd, sdf)
|
||||
sdf.close()
|
||||
|
@ -415,6 +432,8 @@ except KeyError:
|
|||
|
||||
sdref = {'15':'nbrd', '16':'seq', '18':'mas', '21':'urs', '23':'wl', '25':'ipas'} #lookup table (Dictionary)
|
||||
|
||||
gv.now = time.time()+((gv.sd['tz']/4)-12)*3600
|
||||
|
||||
gv.srvals = [0]*(gv.sd['nst']) #Shift Register values
|
||||
|
||||
gv.rovals = [0]* gv.sd['nbrd']*7 #Run Once durations
|
||||
|
@ -480,17 +499,27 @@ def setShiftRegister(srvals):
|
|||
|
||||
##################
|
||||
|
||||
def pass_options(opts):
|
||||
optstring = "var sd = {\n"
|
||||
for o in opts:
|
||||
optstring += "\t" + o + " : "
|
||||
if (type(gv.sd[o]) == unicode):
|
||||
optstring += "'" + gv.sd[o] + "'"
|
||||
else:
|
||||
optstring += str(gv.sd[o])
|
||||
optstring += ",\n"
|
||||
optstring = optstring[:-2] + "\n}\n"
|
||||
return optstring
|
||||
|
||||
#### Class Definitions ####
|
||||
class home:
|
||||
"""Open Home page."""
|
||||
def GET(self):
|
||||
homepg = '<!DOCTYPE html>\n'
|
||||
homepg += data('meta')+'\n'
|
||||
homepg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
homepg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
homepg += data('meta')
|
||||
homepg += '<script>var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
homepg += '<script>var ver=183,devt='+str(gv.now)+';var nbrd='+str(gv.sd['nbrd'])+',tz='+str(gv.sd['tz'])+';</script>\n'
|
||||
homepg += '<script>var en='+str(gv.sd['en'])+',rd='+str(gv.sd['rd'])+',mm='+str(gv.sd['mm'])+',rdst='+str(gv.sd['rdst'])+',mas='+str(gv.sd['mas'])+',urs='+str(gv.sd['urs'])+',rs='+str(gv.sd['rs'])+',ir='+str(gv.sd['ir'])+',wl='+str(gv.sd['wl'])+',ipas='+str(gv.sd['ipas'])+',loc="'+str(gv.sd['loc'])+'";</script>\n'
|
||||
homepg += '<script>var ver='+str(gv.ver)+',devt='+str(gv.now)+';</script>\n'
|
||||
homepg += '<script>' + pass_options(["nbrd","tz","en","rd","rs","mm","rdst","mas","urs","rs","wl","ipas","nopts","loc","name","ir"]) + '</script>\n'
|
||||
homepg += '<script>var sbits='+str(gv.sbits).replace(' ', '')+',ps='+str(gv.ps).replace(' ', '')+';</script>\n'
|
||||
homepg += '<script>var lrun='+str(gv.lrun).replace(' ', '')+';</script>\n'
|
||||
homepg += '<script>var snames='+data('snames')+'; var tempunit="'+str(gv.sd['tu'])+'";</script>\n'
|
||||
|
@ -523,7 +552,6 @@ class change_values:
|
|||
if qdict.has_key('mm') and qdict['mm'] == '0': clear_mm() #self.clear_mm()
|
||||
if qdict.has_key('rd') and qdict['rd'] != '0':
|
||||
gv.sd['rdst'] = (gv.now+(int(qdict['rd'])*3600))
|
||||
#stop_stations()
|
||||
stop_onrain()
|
||||
elif qdict.has_key('rd') and qdict['rd'] == '0': gv.sd['rdst'] = 0
|
||||
if qdict.has_key('rbt') and qdict['rbt'] == '1':
|
||||
|
@ -545,15 +573,8 @@ class view_options:
|
|||
"""Open the options page for viewing and editing."""
|
||||
def GET(self):
|
||||
optpg = '<!DOCTYPE html>\n'
|
||||
optpg += data('meta')+'\n'
|
||||
optpg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
optpg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
optpg += '<script>var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
optpg += '<script>var opts=["Time zone:",0,'+str(gv.sd['tz'])+',1,"HTTP port:",0,'+str(gv.sd['htp'])+',12,"",0,0,13,"Ext. boards:",\
|
||||
0,'+str(gv.sd['nbrd']-1)+',15,"Sequential:",1,'+str(gv.sd['seq'])+',16,"Station delay:",0,'+str(gv.sd['sdt'])+',17,"Master station:",0,'+str(gv.sd['mas'])+',18,"Mas. on adj.:",0,'+str(gv.sd['mton'])+',19,"Mas. off adj.:",0,'+str(gv.sd['mtoff'])+',20,\
|
||||
"Use rain sensor:",1,'+str(gv.sd['urs'])+',21,"Normally open:",1,'+str(gv.sd['rst'])+',22,"Water level (%):",0,'+str(gv.sd['wl'])+',23,\
|
||||
"Ignore password:",1,'+str(gv.sd['ipas'])+',25,0];</script>\n'
|
||||
optpg += '<script>var nopts='+str(gv.sd['nopts'])+',loc="'+str(gv.sd['loc'])+'";</script>\n'
|
||||
optpg += data('meta')
|
||||
optpg += '<script>var baseurl=\"'+baseurl()+'\";\n' + pass_options(["tz","htp","nbrd","sdt","seq","mas","mton","mtoff","urs","wl","ipas","rst","loc","name","lr","lg"]) + data('options')+ '</script>\n'
|
||||
optpg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/viewoptions.js\"></script>'
|
||||
return optpg
|
||||
|
||||
|
@ -562,85 +583,77 @@ class change_options:
|
|||
def GET(self):
|
||||
qdict = web.input()
|
||||
try:
|
||||
if not qdict.has_key('o25') and qdict['pw'] != base64.b64decode(gv.sd['pwd']):
|
||||
if gv.sd['ipas'] == 0 and qdict['pw'] != base64.b64decode(gv.sd['pwd']):
|
||||
raise web.unauthorized()
|
||||
return
|
||||
elif qdict.has_key('o25') and gv.sd['ipas'] == 0 and qdict['pw'] != base64.b64decode(gv.sd['pwd']):
|
||||
raise web.unauthorized()
|
||||
return
|
||||
elif qdict.has_key('o25') and gv.sd['ipas'] == 0 and qdict['pw'] == base64.b64decode(gv.sd['pwd']):
|
||||
if qdict.has_key('oipas') and (qdict['oipas'] == 'on' or qdict['oipas'] == ''):
|
||||
gv.sd['ipas'] = 1
|
||||
else:
|
||||
gv.sd['ipas'] = 0
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
if qdict['cpw'] !='' and qdict['cpw'] == qdict['npw']:
|
||||
gv.sd['pwd'] = base64.b64encode(qdict['npw'])
|
||||
except KeyError:
|
||||
pass
|
||||
vstr = data('options')
|
||||
if vstr.find("Sequential:") == -1:
|
||||
os.remove("./data/options.txt")
|
||||
vstr = data('options')
|
||||
ops = vstr.index('[')+1
|
||||
ope = vstr.index(']')
|
||||
optstr = vstr[ops:ope]
|
||||
optlst = optstr.split(',')
|
||||
onumlst = []
|
||||
i=3
|
||||
while i < len(optlst):
|
||||
onumlst.append(optlst[i].replace(' ', ''))
|
||||
if optlst[i-2] == '1': #clear check box items
|
||||
optlst[i-1]= '0'
|
||||
try:
|
||||
sdref[optlst[i]];
|
||||
gv.sd[sdref[optlst[i]]]=0
|
||||
except KeyError:
|
||||
pass
|
||||
i+=4
|
||||
for key in qdict.keys():
|
||||
if key[:1] == 'o':
|
||||
oidx = onumlst.index(key[1:])
|
||||
if qdict[key] == 'on' or '':
|
||||
qdict[key] = '1'
|
||||
optlst[(oidx*4)+2] = qdict[key]
|
||||
optstr = ','.join(optlst)
|
||||
optstr = optstr.replace(', ', ',')
|
||||
vstr = vstr.replace(vstr[ops:ope], optstr)
|
||||
save('options', vstr)
|
||||
if int(qdict['o15'])+1 != gv.sd['nbrd']: self.update_scount(qdict)
|
||||
if int(qdict['o18']) != gv.sd['mas']:
|
||||
clear_mm()
|
||||
self.update_sd(qdict)
|
||||
pass
|
||||
|
||||
gv.sd['name'] = qdict['oname']
|
||||
gv.sd['loc'] = qdict['oloc']
|
||||
gv.sd['tz'] = int(qdict['otz'])
|
||||
|
||||
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
|
||||
gv.sd['htp']= int(qdict['ohtp'])
|
||||
gv.sd['sdt']= int(qdict['osdt'])
|
||||
|
||||
gv.sd['mas'] = int(qdict['omas'])
|
||||
gv.sd['mton']= int(qdict['omton'])
|
||||
gv.sd['mtoff']= int(qdict['omtoff'])
|
||||
gv.sd['wl'] = int(qdict['owl'])
|
||||
|
||||
if qdict.has_key('ours') and (qdict['ours'] == 'on' or qdict['ours'] == ''):
|
||||
gv.sd['urs'] = 1
|
||||
else:
|
||||
gv.sd['urs'] = 0
|
||||
|
||||
if qdict.has_key('oseq') and (qdict['oseq'] == 'on' or qdict['oseq'] == ''):
|
||||
gv.sd['seq'] = 1
|
||||
else:
|
||||
gv.sd['seq'] = 0
|
||||
|
||||
if qdict.has_key('orst') and (qdict['orst'] == 'on' or qdict['orst'] == ''):
|
||||
gv.sd['rst'] = 1
|
||||
else:
|
||||
gv.sd['rst'] = 0
|
||||
|
||||
if qdict.has_key('olg') and (qdict['olg'] == 'on' or qdict['olg'] == ''):
|
||||
gv.sd['lg'] = 1
|
||||
else:
|
||||
gv.sd['lg'] = 0
|
||||
gv.lg = gv.sd['lg'] # necessary to make logging work correctly on Pi (see run_log())
|
||||
|
||||
gv.sd['lr'] = int(qdict['olr'])
|
||||
gv.lr = gv.sd['lr']
|
||||
|
||||
srvals = [0]*(gv.sd['nst']) # Shift Register values
|
||||
rovals = [0]*(gv.sd['nst']) # Run Once Durations
|
||||
jsave(gv.sd, 'sd')
|
||||
|
||||
raise web.seeother('/')
|
||||
#alert = '<script>alert("Options values saved.");window.location="/";</script>'
|
||||
return #alert # -- Alerts are not considered good interface progrmming. Use sparingly!
|
||||
|
||||
def update_sd(self, qdict):
|
||||
"""Transfer user input to vars."""
|
||||
gv.sd['htp'] = int(qdict['htp'])
|
||||
gv.sd['nbrd'] = int(qdict['o15'])+1
|
||||
gv.sd['nst'] = gv.sd['nbrd']*8
|
||||
gv.sd['sdt']= int(qdict['o17'])
|
||||
gv.sd['mas'] = int(qdict['o18'])
|
||||
gv.sd['mton']= int(qdict['o19'])
|
||||
gv.sd['mtoff']= int(qdict['o20'])
|
||||
gv.sd['tz'] = int(qdict['o1'])
|
||||
if qdict.has_key('o16'): gv.sd['seq'] = int(qdict['o16'])
|
||||
if qdict.has_key('o21'): gv.sd['urs'] = int(qdict['o21'])
|
||||
gv.sd['wl'] = int(qdict['o23'])
|
||||
if qdict.has_key('o25'): gv.sd['ipas'] = int(qdict['o25'])
|
||||
gv.sd['loc'] = qdict['loc']
|
||||
gv.srvals = [0]*(gv.sd['nst']) # Shift Register values
|
||||
gv.rovals = [0]*(gv.sd['nst']) # Run Once Durations
|
||||
jsave(gv.sd, 'sd')
|
||||
return
|
||||
|
||||
def update_scount(self, qdict):
|
||||
"""Increase or decrease the number of stations shown when expansion boards are added in options."""
|
||||
if int(qdict['o15'])+1 > gv.sd['nbrd']: # Lengthen lists
|
||||
incr = int(qdict['o15']) - (gv.sd['nbrd']-1)
|
||||
if int(qdict['onbrd'])+1 > gv.sd['nbrd']: # Lengthen lists
|
||||
incr = int(qdict['onbrd']) - (gv.sd['nbrd']-1)
|
||||
for i in range(incr):
|
||||
gv.sd['mo'].append(0)
|
||||
for i in range(incr):
|
||||
gv.sd['ir'].append(0)
|
||||
snames = data('snames')
|
||||
nlst = re.findall('[\'"].*?[\'"]', snames)
|
||||
ln = len(nlst)
|
||||
|
@ -649,35 +662,36 @@ class change_options:
|
|||
nlst.append("'S"+('%d'%(i+ln)).zfill(2)+"'")
|
||||
nstr = '['+','.join(nlst)
|
||||
nstr = nstr.replace("', ", "',")+",'']"
|
||||
save('snames', nstr)
|
||||
elif int(qdict['o15'])+1 < gv.sd['nbrd']: # Shorten lists
|
||||
decr = gv.sd['nbrd'] - (int(qdict['o15'])+1)
|
||||
gv.sd['mo'] = gv.sd['mo'][:(int(qdict['o15'])+1)]
|
||||
save('snames', nstr)
|
||||
for i in range(incr*8):
|
||||
gv.srvals.append(0)
|
||||
gv.ps.append([0,0])
|
||||
gv.rs.append([0,0,0,0])
|
||||
for i in range(incr):
|
||||
gv.sbits.append(0)
|
||||
elif int(qdict['onbrd'])+1 < gv.sd['nbrd']: # Shorten lists
|
||||
onbrd = qdict['onbrd']
|
||||
decr = gv.sd['nbrd'] - (onbrd+1)
|
||||
gv.sd['mo'] = gv.sd['mo'][:(onbrd+1)]
|
||||
gv.sd['ir'] = gv.sd['ir'][:(onbrd+1)]
|
||||
snames = data('snames')
|
||||
nlst = re.findall('[\'"].*?[\'"]', snames)
|
||||
nstr = '['+','.join(nlst[:8+(int(qdict['o15'])*8)])+','']'
|
||||
nstr = '['+','.join(nlst[:8+(onbrd*8)])+','']'
|
||||
save('snames', nstr)
|
||||
gv.srvals = [0] * (int(qdict['o15'])+1) * 8
|
||||
gv.ps = []
|
||||
for i in range((int(qdict['o15'])+1) * 8):
|
||||
gv.ps.append([0,0])
|
||||
gv.rs = []
|
||||
for i in range((int(qdict['o15'])+1) * 8):
|
||||
gv.rs.append([0,0,0,0])
|
||||
gv.sbits = [0] * (int(qdict['o15'])+2)
|
||||
return
|
||||
newlen = gv.sd['nst'] - decr * 8
|
||||
gv.srvals = gv.srvals[:newlen]
|
||||
gv.ps = gv.ps[:newlen]
|
||||
gv.rs = gv.rs[:newlen]
|
||||
gv.sbits = gv.sbits[:onbrd+1]
|
||||
return
|
||||
|
||||
class view_stations:
|
||||
"""Open a page to view and edit station names and master associations."""
|
||||
def GET(self):
|
||||
stationpg = '<!DOCTYPE html>\n'
|
||||
stationpg += data('meta')+'\n'
|
||||
stationpg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
stationpg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
stationpg += data('meta')
|
||||
stationpg += '<script>var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
stationpg += '<script>var nboards='+str(gv.sd['nbrd'])+',maxlen=12,mas='+str(gv.sd['mas'])+',ipas='+str(gv.sd['ipas'])+';</script>\n'
|
||||
#stationpg += '<script>var masop='+str(gv.sd['mo'])+';</script>\n'
|
||||
stationpg += '<script>var masop='+str(gv.sd['mo'])+',rop='+str(gv.sd['ir'])+';</script>\n' ## added experimental "Ignore Rain"' feature
|
||||
stationpg += '<script>var baseurl=\"'+baseurl()+'\"\n' + pass_options(["nbrd","snlen","mas","ipas","mo","ir"]) + '</script>\n'
|
||||
stationpg += '<script>snames='+data('snames')+';</script>\n'
|
||||
stationpg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/viewstations.js\"></script>'
|
||||
return stationpg
|
||||
|
@ -686,7 +700,6 @@ class change_stations:
|
|||
"""Save changes to station names and master associations."""
|
||||
def GET(self):
|
||||
qdict = web.input()
|
||||
print qdict
|
||||
try:
|
||||
if gv.sd['ipas'] != 1 and qdict['pw'] != base64.b64decode(gv.sd['pwd']):
|
||||
raise web.unauthorized()
|
||||
|
@ -755,17 +768,15 @@ class view_runonce:
|
|||
"""Open a page to view and edit a run once program."""
|
||||
def GET(self):
|
||||
ropg = '<!DOCTYPE html>\n'
|
||||
ropg += data('meta')+'\n'
|
||||
ropg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
ropg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
ropg += '<script >var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
ropg += '<script >var nboards='+str(gv.sd['nbrd'])+',mas='+str(gv.sd['mas'])+',ipas='+str(gv.sd['ipas'])+',dur='+str(gv.rovals).replace(' ', '')+';</script>\n'
|
||||
ropg += data('meta')
|
||||
ropg += '<script >var baseurl=\"'+baseurl()+'\"\n' + pass_options(["nbrd","mas","ipas"]) + '</script>\n'
|
||||
ropg += '<script >var dur='+str(gv.rovals).replace(' ', '')+';</script>\n'
|
||||
ropg += '<script >snames='+data('snames')+';</script>\n'
|
||||
ropg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/viewro.js\"></script>'
|
||||
return ropg
|
||||
|
||||
class change_runonce:
|
||||
"""Start a Run Once program. This wil. override any running program."""
|
||||
"""Start a Run Once program. This will override any running program."""
|
||||
def GET(self):
|
||||
qdict = web.input()
|
||||
try:
|
||||
|
@ -777,12 +788,12 @@ class change_runonce:
|
|||
if not gv.sd['en']: return # check operation status
|
||||
gv.rovals = json.loads(qdict['t'])
|
||||
gv.rovals.pop()
|
||||
gv.ps = []
|
||||
stations = [0] * gv.sd['nbrd']
|
||||
gv.ps = [] # program schedule (for display)
|
||||
gv.rs = [] # run schedule
|
||||
for i in range(gv.sd['nst']):
|
||||
gv.ps.append([0,0])
|
||||
gv.rs = [] #run schedule
|
||||
for i in range(gv.sd['nst']): # clear run schedule
|
||||
gv.rs.append([0,0,0,0])
|
||||
gv.rs.append([0,0,0,0])
|
||||
for i, v in enumerate(gv.rovals):
|
||||
if v: # if this element has a value
|
||||
gv.rs[i][0] = gv.now
|
||||
|
@ -790,18 +801,17 @@ class change_runonce:
|
|||
gv.rs[i][3] = 98
|
||||
gv.ps[i][0] = 98
|
||||
gv.ps[i][1] = v
|
||||
schedule_stations()
|
||||
stations[i/8] += 2**(i%8)
|
||||
schedule_stations(stations)
|
||||
raise web.seeother('/')
|
||||
|
||||
class view_programs:
|
||||
"""Open programs page."""
|
||||
def GET(self):
|
||||
programpg = '<!DOCTYPE html>\n'
|
||||
programpg += data('meta')+'\n'
|
||||
programpg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
programpg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
programpg += data('meta')
|
||||
programpg += '<script >var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
programpg += '<script >'+output_prog()+'</script>\n'
|
||||
programpg += '<script >'+ pass_options(["nbrd","ipas","mnp"]) + output_prog()+'</script>\n'
|
||||
programpg += '<script >snames='+data('snames')+';</script>\n'
|
||||
programpg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/viewprog.js\"></script>'
|
||||
return programpg
|
||||
|
@ -811,11 +821,8 @@ class modify_program:
|
|||
def GET(self):
|
||||
qdict = web.input()
|
||||
modprogpg = '<!DOCTYPE html>\n'
|
||||
modprogpg += data('meta')+'\n'
|
||||
modprogpg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
modprogpg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
modprogpg += '<script >var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
modprogpg += '<script >var nboards='+str(gv.sd['nbrd'])+',ipas='+str(gv.sd['ipas'])+';\n'
|
||||
modprogpg += data('meta')
|
||||
modprogpg += '<script >var baseurl=\"'+baseurl()+'\"\n' + pass_options(["nbrd","ipas"]) + '\n'
|
||||
if qdict['pid'] != '-1':
|
||||
mp = gv.pd[int(qdict['pid'])][:]
|
||||
if mp[1] >= 128 and mp[2] > 1: # If this is an interval program
|
||||
|
@ -898,15 +905,11 @@ class graph_programs:
|
|||
else: mm = str(lt.tm_mon)
|
||||
if qdict.has_key('y'): yy = str(qdict['y'])
|
||||
else: yy = str(lt.tm_year)
|
||||
graphpg = '<script >var baseurl=\"'+baseurl()+'\"</script>\n'
|
||||
graphpg += '<link href="./static/images/icons/favicon.ico" rel="icon" type="image/x-icon" />\n'
|
||||
graphpg += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
graphpg += ('<script >var mas='+str(gv.sd['mas'])+',wl='+str(gv.sd['wl'])+',sdt='+str(gv.sd['sdt'])+
|
||||
',mton='+str(gv.sd['mton'])+',mtoff='+str(gv.sd['mtoff'])+',devday='+str(int(t/86400))+
|
||||
',devmin='+str((lt.tm_hour*60)+lt.tm_min)+',dd='+dd+',mm='+mm+',yy='+yy+';var masop='+
|
||||
str(gv.sd['mo'])+';'+output_prog()+'</script>\n')
|
||||
graphpg += '<script>var seq='+str(gv.sd['seq'])+';</script>\n'
|
||||
graphpg += '<script >var snames='+data('snames').replace(' ', '')+';</script>\n'
|
||||
graphpg = '<!DOCTYPE html>\n'
|
||||
graphpg += data('meta')
|
||||
graphpg += '<script>var baseurl=\"'+baseurl()+'\";\n' + pass_options(["mas","seq","wl","sdt","mton","mtoff","nbrd","ipas","mnp","mo"]) + '</script>\n'
|
||||
graphpg += '<script>var devday='+str(int(t/86400))+',devmin='+str((lt.tm_hour*60)+lt.tm_min)+',dd='+dd+',mm='+mm+',yy='+yy+';'+output_prog()+'</script>\n'
|
||||
graphpg += '<script>var snames='+data('snames').replace(' ', '')+';</script>\n'
|
||||
graphpg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/plotprog.js\"></script>'
|
||||
return graphpg
|
||||
|
||||
|
@ -950,10 +953,10 @@ class log_options:
|
|||
return
|
||||
except KeyError:
|
||||
pass
|
||||
if qdict.has_key('log'): gv.sd['lg'] = "checked"
|
||||
else: gv.sd['lg'] = ""
|
||||
if qdict.has_key('log'): gv.sd['lg'] = 1
|
||||
else: gv.sd['lg'] = 0
|
||||
gv.lg = gv.sd['lg'] # necessary to make logging work correctly on Pi (see run_log())
|
||||
gv.sd['lr'] = qdict['nrecords']
|
||||
gv.sd['lr'] = int(qdict['nrecords'])
|
||||
gv.lr = int(gv.sd['lr'])
|
||||
jsave(gv.sd, 'sd')
|
||||
raise web.seeother('/vl')
|
||||
|
@ -973,7 +976,8 @@ class run_now:
|
|||
if not p[0]: # if program is disabled
|
||||
raise web.seeother('/vp')
|
||||
stop_stations()
|
||||
for b in range(gv.sd['nbrd']): # check each station
|
||||
#for b in range(gv.sd['nbrd']): # check each station
|
||||
for b in range(len(p[7:7+gv.sd['nbrd']])): # check each station
|
||||
for s in range(8):
|
||||
sid = b*8+s # station index
|
||||
if sid+1 == gv.sd['mas']: continue # skip if this is master valve
|
||||
|
@ -982,11 +986,21 @@ class run_now:
|
|||
gv.rs[sid][3] = pid+1 # store program number in schedule
|
||||
gv.ps[sid][0] = pid+1 # store program number for display
|
||||
gv.ps[sid][1] = gv.rs[sid][2] # duration
|
||||
schedule_stations()
|
||||
schedule_stations(p[7:7+gv.sd['nbrd']])
|
||||
raise web.seeother('/')
|
||||
|
||||
class show_revision:
|
||||
"""Show revision info to the user. Use: [URL of Pi]/rev."""
|
||||
def GET(self):
|
||||
revpg = '<!DOCTYPE html>\n'
|
||||
revpg += 'Python Interval Program for OpenSprinkler Pi<br/><br/>\n'
|
||||
revpg += 'Compatable with OpenSprinkler firmware 1.8.3.<br/><br/>\n'
|
||||
revpg += 'ospi.py revision: '+str(gv.rev) +'<br/><br/>\n'
|
||||
revpg += 'updated ' + gv.rev_date +'\n'
|
||||
return revpg
|
||||
|
||||
class toggle_temp:
|
||||
"""Change units of Raspi's CPU temperature display on home page."""
|
||||
"""Change units of Raspi\'s CPU temperature display on home page."""
|
||||
def GET(self):
|
||||
qdict = web.input()
|
||||
if qdict['tunit'] == "C":
|
||||
|
@ -1000,7 +1014,8 @@ class OSPi_app(web.application):
|
|||
"""Allows HTTP port the program runs on to be selected by the program."""
|
||||
def run(self, port=gv.sd['htp'], *middleware): # get port number from options settings
|
||||
func = self.wsgifunc(*middleware)
|
||||
return web.httpserver.runsimple(func, ('0.0.0.0', port))
|
||||
return web.httpserver.runsimple(func, ('0.0.0.0', port))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = OSPi_app(urls, globals())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Vars held in the settings dict (gv.sd)
|
||||
??Vars held in the settings dict (gv.sd)
|
||||
|
||||
from controller values (cvalues):
|
||||
en:1 enabled (operation)
|
||||
|
@ -7,23 +7,25 @@ mm:0 manual mode (bool)
|
|||
rbt:0 reboot (bool)
|
||||
|
||||
from options:
|
||||
htp:8080 http port the program will run on (o12)
|
||||
seq:1 sequential/concurrent operation (o16)
|
||||
sdt:0 station delay time(o17)
|
||||
mton:0 master on delay (o19)
|
||||
mtoff:0 master off delay (020)
|
||||
nbrd:1 number of boards (o15)
|
||||
tz:16 time zone (o1)
|
||||
urs:0 use rain sensor (o21 - not used)
|
||||
rst:1 Rain sensor type (normaly open =1, dafault, or closed, o22 - not used)
|
||||
wl:100 water level (percent, o23)
|
||||
mas:0 master station index (o18)
|
||||
ipas:1 ignore passwprd (bool, o25)
|
||||
htp:8080 http port the program will run on
|
||||
seq:1 sequential/concurrent operation
|
||||
sdt:0 station delay time
|
||||
mton:0 master on delay
|
||||
mtoff:0 master off delay
|
||||
nbrd:1 number of boards
|
||||
tz:16 time zone
|
||||
urs:0 use rain sensor
|
||||
rst:1 Rain sensor type (normaly open =1, dafault, or closed - not used)
|
||||
wl:100 water level (percent)
|
||||
mas:0 master station index
|
||||
ipas:1 ignore passwprd (bool)
|
||||
pwd:"b3BlbmRvb3I=" encoded password (default shown here)
|
||||
loc:"" location (for weather - not used)
|
||||
rdst:0 rain delay stop time (unix time stamp)
|
||||
rs:0 rain sensed (o22)
|
||||
nopts:13 Number of optiions to be displayed
|
||||
rs:0 rain sensed
|
||||
nopts:14 Number of optiions to be displayed
|
||||
name:"OpenSprinkler Pi" configurable name for system
|
||||
snlen:32 max size of station names
|
||||
|
||||
for scheduling:
|
||||
bsy:0 program buisy
|
||||
|
|
|
@ -10,7 +10,7 @@ function linkn(s){window.open(s, '_blank');}
|
|||
// input rain delay value
|
||||
function setrd(form,idx) {var h=prompt("Enter hours to delay","0");if(h!=null){form.elements[idx].value=h;form.submit()};}
|
||||
function imgstr(s) {return "<img src=\""+baseurl+"/static/images/icons/svc_"+s+".png\" height=20 align=absmiddle> ";}
|
||||
function datestr(t) {var _t=tz-48; return (new Date(t)).toUTCString()+((_t>=0)?"+":"-")+(Math.abs(_t)/4>>0)+":"+((Math.abs(_t)%4)*15/10>>0)+((Math.abs(_t)%4)*15%10);}
|
||||
function datestr(t) {var _t=sd['tz']-48; return (new Date(t)).toUTCString()+((_t>=0)?"+":"-")+(Math.abs(_t)/4>>0)+":"+((Math.abs(_t)%4)*15/10>>0)+((Math.abs(_t)%4)*15%10);}
|
||||
// raspi CPU temp unit
|
||||
function toggle(form) {form.elements[0].value=tempunit;form.submit();}
|
||||
w("<form name=tt action=ttu method=get><input type=hidden name=tunit></form>");
|
||||
|
@ -27,31 +27,33 @@ w("<button style=\"height:44\" onclick=link(\"/vp\")>"+imgstr("cal")+"Programs</
|
|||
//w("<button style=\"height:44\" onclick=linkn(\"http://igoogle.wunderground.com/cgi-bin/findweather/getForecast?query="+loc+"\")>"+imgstr("weather")+"Weather</button><p></p>");
|
||||
w("<button style=\"height:44\" onclick=link(\"/vl\")>"+imgstr("log")+"Log</button><p></p>");
|
||||
// print device information
|
||||
w("<b>System name</b>: "+sd['name']+"<br>");
|
||||
if(ver>=100) w("<b>Firmware version</b>: "+(ver/100>>0)+"."+((ver/10>>0)%10)+"."+(ver%10)+"<br>");
|
||||
else w("<b>Firmware version</b>: "+(ver/10>>0)+"."+(ver%10)+"<br>");
|
||||
w("<b>Device time</b>: "+datestr(devt*1000)+"<br>");
|
||||
|
||||
if (typeof cputemp === 'undefined') cputemp="";
|
||||
w("<b>CPU Temp</b>: <span id='heat' onmouseover='bluebg(this)' onmouseout='nobg(this)' style='cursor:pointer' onclick='toggle(tt)' title='Click to toggle Celsius <> Fahrenheit'>"+cputemp+"°"+tempunit+"</span><hr>");
|
||||
w("<script type=\"text/javascript\" src=\""+baseurl+"/static/scripts/java/svc1.8.3/"+((mm)?"manualmode.js":"progmode.js")+"\"></script>");
|
||||
w("<script type=\"text/javascript\" src=\""+baseurl+"/static/scripts/java/svc1.8.3/"+((sd['mm'])?"manualmode.js":"progmode.js")+"\"></script>");
|
||||
// print status and other information
|
||||
w("<br><b>Operation</b>: "+(en?("on").fontcolor("green"):("OFF").fontcolor("red")));
|
||||
w("<br><b>Raindelay</b>: "+(rd?("ON").fontcolor("red")+" (till "+datestr(rdst*1000)+")":("off").fontcolor("black")));
|
||||
w("<br><b>Rainsense</b>: "+(urs?(rs?("Rain Detected").fontcolor("red"):("no rain").fontcolor("green")):"<font color=gray>n/a</font>"));
|
||||
w("<br><b>Water level</b>: <font color="+((wl==100)?"green":"red")+">"+wl+"\%</font>");
|
||||
w("<br><b>Operation</b>: "+(sd['en']?("on").fontcolor("green"):("OFF").fontcolor("red")));
|
||||
w("<br><b>Raindelay</b>: "+(sd['rd']?("ON").fontcolor("red")+" (till "+datestr(rdst*1000)+")":("off").fontcolor("black")));
|
||||
w("<br><b>Rainsense</b>: "+(sd['urs']?(sd['rs']?("Rain Detected").fontcolor("red"):("no rain").fontcolor("green")):"<font color=gray>n/a</font>"));
|
||||
w("<br><b>Water level</b>: <font color="+((sd['wl']==100)?"green":"red")+">"+sd['wl']+"\%</font>");
|
||||
var lrsid=lrun[0],lrpid=lrun[1],lrdur=lrun[2],lret=lrun[3];
|
||||
var pname="P"+lrpid;
|
||||
if(lrpid==255||lrpid==99) pname="Manual Mode";
|
||||
if(lrpid==254||lrpid==98) pname="Run-once Program";
|
||||
dstr=(new Date(lret*1000)).toUTCString().replace(" GMT","");
|
||||
//dstr=(new Date(lret*1000)).toUTCString().replace(" GMT","");
|
||||
dstr=(new Date(lret*1000)).toUTCString()+(((sd['tz']-48)>=0)?"+":"-")+(Math.abs(sd['tz']-48)/4>>0)+":"+((Math.abs(sd['tz']-48)%4)*15/10>>0)+((Math.abs(sd['tz']-48)%4)*15%10);
|
||||
if(lrpid!=0) w("<br><b>Log</b>: "+(snames[lrsid]+" ran "+pname+" for "+(lrdur/60>>0)+"m"+(lrdur%60)+"s @ "+dstr).fontcolor("gray"));
|
||||
else w("<br><b>Log</b>: <font color=gray>n/a</font>");
|
||||
w("<hr>");
|
||||
// print html form
|
||||
w("<form name=hf action=cv method=get><p>Password:<input type=password "+(ipas?"disabled":"")+" size=10 id=pwd name=pw></p>");
|
||||
w("<form name=hf action=cv method=get><p>Password:<input type=password "+(sd['ipas']?"disabled":"")+" size=10 id=pwd name=pw></p>");
|
||||
w("<input type=hidden name=en><input type=hidden name=rd value=0><input type=hidden name=rbt value=0><input type=hidden name=mm value=0></form>");
|
||||
w("<button style=\"height:36\" onclick=\"hf.elements[1].value="+(1-en)+";hf.submit();\">"+imgstr(en?"stop":"start")+(en?"Stop Operation":"Start Operation")+"</button>");
|
||||
w("<button style=\"height:36\" onclick=\"hf.elements[4].value="+(1-mm)+";hf.submit();\">"+imgstr(mm?"auto":"manual")+(mm?"Manual Off":"Manual On")+"</button>");
|
||||
w("<button style=\"height:36\" onclick=\"hf.elements[1].value="+(1-sd['en'])+";hf.submit();\">"+imgstr(sd['en']?"stop":"start")+(sd['en']?"Stop Operation":"Start Operation")+"</button>");
|
||||
w("<button style=\"height:36\" onclick=\"hf.elements[4].value="+(1-sd['mm'])+";hf.submit();\">"+imgstr(sd['mm']?"auto":"manual")+(sd['mm']?"Manual Off":"Manual On")+"</button>");
|
||||
w("<button style=\"height:36\" onclick=\"setrd(hf,2)\">"+imgstr("rain")+"Rain Delay</button>");
|
||||
w("<button style=\"height:36\" onclick=\"hf.elements[3].value=1;hf.submit();\">"+imgstr("reboot")+"Reboot</button>");
|
||||
w("<p></p><hr><br>");
|
||||
|
|
|
@ -18,14 +18,14 @@ function snf(sid,sbit) {
|
|||
w("<b>Manual Control:</b> (timer is optional)<p></p>");
|
||||
w("<table border=1>");
|
||||
var bid,s,sid,sn,rem,remm,rems,sbit;
|
||||
for(bid=0;bid<nbrd;bid++){
|
||||
for(bid=0;bid<sd['nbrd'];bid++){
|
||||
for(s=0;s<8;s++){
|
||||
w("<tr><td bgcolor='#E4E4E4'>");
|
||||
sid=bid*8+s;
|
||||
sn=sid+1;
|
||||
//w("Station "+(sn/10>>0)+(sn%10)+": ");
|
||||
w(snames[sid]+": </td><td>");
|
||||
if(sn==mas) {w(((sbits[bid]>>s)&1?("<b>On</b>").fontcolor("green"):("Off").fontcolor("black"))+" (<b>Master</b>)");}
|
||||
if(sn==sd['mas']) {w(((sbits[bid]>>s)&1?("<b>On</b>").fontcolor("green"):("Off").fontcolor("black"))+" (<b>Master</b>)");}
|
||||
else {
|
||||
rem=ps[sid][1];
|
||||
if(rem>65536) rem=0;
|
||||
|
|
|
@ -45,7 +45,7 @@ function fsubmit(f) {
|
|||
if(days[0]==0||(days[1]<2&&(days[0]&0x7f)==0)) {alert("Error: You have not selected any day.");return;}
|
||||
// process stations
|
||||
var stations=[0],station_selected=0,bid;
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
stations[bid]=0;
|
||||
for(s=0;s<8;s++) {
|
||||
sid=bid*8+s;
|
||||
|
@ -67,12 +67,12 @@ function fsubmit(f) {
|
|||
if(!(dm>=0&&ds>=0&&ds<60&&duration>0)) {alert("Error: Incorrect duration.");return;}
|
||||
// password
|
||||
var p="";
|
||||
if(!ipas) p=prompt("Please enter your password:","");
|
||||
if(!sd['ipas']) p=prompt("Please enter your password:","");
|
||||
if(p!=null){
|
||||
f.elements[0].value=p;
|
||||
f.elements[1].value=pid;
|
||||
f.elements[2].value="["+en+","+days[0]+","+days[1]+","+start_time+","+end_time+","+interval+","+duration;
|
||||
for(i=0;i<nboards;i++) {f.elements[2].value+=","+stations[i];}
|
||||
for(i=0;i<sd['nbrd'];i++) {f.elements[2].value+=","+stations[i];}
|
||||
f.elements[2].value+="]";
|
||||
f.submit();
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ w("<input type=radio name=rad_day id=days_n><b><u>Interval</u>:</b> Every <input
|
|||
w("<p><b>Select Stations:</b></p>");
|
||||
w("<table border=1 cellpadding=3>");
|
||||
var bid,s,sid;
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
for(s=0;s<8;s++) {
|
||||
sid=bid*8+s;
|
||||
if(sid%4==0) w("<tr>");
|
||||
|
@ -135,7 +135,7 @@ if(pid>-1) {
|
|||
id("tds").value=""+((t%60)/10>>0)+((t%60)%10);
|
||||
// process stations
|
||||
var bits;
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
bits=prog[bid+7];
|
||||
for(s=0;s<8;s++) {sid=bid*8+s;id("s"+sid).checked=(bits&(1<<s)?true:false);}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
var prog_color=["rgba(0,0,200,0.5)","rgba(0,200,0,0.5)","rgba(200,0,0,0.5)","rgba(0,200,200,0.5)"];
|
||||
var days_str=["Sun","Mon","Tue","Wed","Thur","Fri","Sat"];
|
||||
var xstart=80,ystart=80,stwidth=40,stheight=180;
|
||||
var winwidth=stwidth*nboards*8+xstart, winheight=26*stheight+ystart;
|
||||
var winwidth=stwidth*sd['nbrd']*8+xstart, winheight=26*stheight+ystart;
|
||||
var sid,sn,t;
|
||||
var simt=Date.UTC(yy,mm-1,dd,0,0,0,0);
|
||||
var simdate=new Date(simt);
|
||||
|
@ -50,39 +50,39 @@ function getrunstr(start,end){ // run time string
|
|||
return str;
|
||||
}
|
||||
function plot_bar(sid,start,pid,end) { // plot program bar
|
||||
w("<div title=\""+snames[sid]+" ["+getrunstr(start,end)+"]\" align=\"center\" style=\"position:absolute;background-color:"+prog_color[(pid+3)%4]+";left:"+getx(sid)+";top:"+gety(start/60)+";border:0;width:"+stwidth+";height:"+((end-start)/60*stheight/60)+"\">P"+pid+"</div>");
|
||||
w("<div title=\""+snames[sid]+" ["+getrunstr(start,end)+"]\" align=\"center\" style=\"position:absolute;background-color:"+prog_color[(pid+3)%4]+";left:"+getx(sid)+"px;top:"+gety(start/60)+"px;border:0;width:"+stwidth+"px;height:"+((end-start)/60*stheight/60)+"px\">P"+pid+"</div>");
|
||||
}
|
||||
function plot_master(start,end) { // plot master station
|
||||
w("<div title=\"Master ["+getrunstr(start,end)+"]\" style=\"position:absolute;background-color:#CCCC80;left:"+getx(mas-1)+";top:"+gety(start/60)+";border:0;width:"+stwidth+";height:"+((end-start)/60*stheight/60)+"\"></div>");
|
||||
w("<div title=\"Master ["+getrunstr(start,end)+"]\" style=\"position:absolute;background-color:#CCCC80;left:"+getx(mas-1)+"px;top:"+gety(start/60)+"px;border:0;width:"+stwidth+"px;height:"+((end-start)/60*stheight/60)+"px\"></div>");
|
||||
//if(mas==0||start==end) return;
|
||||
//ctx.fillStyle="rgba(64,64,64,0.5)";
|
||||
//ctx.fillRect(getx(mas-1),gety(start/60),stwidth,(end-start)/60*stheight/60);
|
||||
}
|
||||
function plot_currtime() {
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-10)+";top:"+gety(devmin)+";border:1px solid rgba(200,0,0,0.5);width:"+(winwidth-xstart+stwidth/2)+";height:0;\"></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-10)+"px;top:"+gety(devmin)+"px;border:1px solid rgba(200,0,0,0.5);width:"+(winwidth-xstart+stwidth/2)+"px;height:0px;\"></div>");
|
||||
}
|
||||
function run_sched(simseconds,st_array,pid_array,et_array) { // run and plot schedule stored in array data
|
||||
var sid,endtime=simseconds;
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
if(pid_array[sid]) {
|
||||
if(seq==1) { // sequential
|
||||
if(sd['seq']==1) { // sequential
|
||||
plot_bar(sid,st_array[sid],pid_array[sid],et_array[sid]);
|
||||
if((mas>0)&&(mas!=sid+1)&&(masop[sid>>3]&(1<<(sid%8))))
|
||||
plot_master(st_array[sid]+mton, et_array[sid]+mtoff);
|
||||
if((sd['mas']>0)&&(sd['mas']!=sid+1)&&(sd['mo'][sid>>3]&(1<<(sid%8))))
|
||||
plot_master(st_array[sid]+sd['mton'], et_array[sid]+sd['mtoff']);
|
||||
endtime=et_array[sid];
|
||||
} else { // concurrent
|
||||
plot_bar(sid,simseconds,pid_array[sid],et_array[sid]);
|
||||
// check if this station activates master
|
||||
if((mas>0)&&(mas!=sid+1)&&(masop[sid>>3]&(1<<(sid%8))))
|
||||
if((sd['mas']>0)&&(sd['mas']!=sid+1)&&(sd['mo'][sid>>3]&(1<<(sid%8))))
|
||||
endtime=(endtime>et_array[sid])?endtime:et_array[sid];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(seq==0&&mas>0) plot_master(simseconds,endtime);
|
||||
if(sd['seq']==0&&sd['mas']>0) plot_master(simseconds,endtime);
|
||||
return endtime;
|
||||
}
|
||||
function draw_title() {
|
||||
w("<div align=\"center\" style=\"background-color:#EEEEEE;position:absolute;left:0px;top:10px;border:2px solid gray;padding:5px 0px;width:"+(winwidth)+";border-radius:10px;box-shadow:3px 3px 2px #888888;\"><b>Program Preview of</b> ");
|
||||
w("<div align=\"center\" style=\"background-color:#EEEEEE;position:absolute;left:0px;top:10px;border:2px solid gray;padding:5px 0px;width:"+(winwidth)+"px;border-radius:10px;box-shadow:3px 3px 2px #888888;\"><b>Program Preview of</b> ");
|
||||
w(days_str[simdate.getUTCDay()]+" "+(simdate.getUTCMonth()+1)+"/"+(simdate.getUTCDate())+" "+(simdate.getUTCFullYear()));
|
||||
w("<br><font size=2>(Hover over each colored bar to see tooltip)</font>");
|
||||
w("</div>");
|
||||
|
@ -90,25 +90,25 @@ function draw_title() {
|
|||
|
||||
function draw_grid() {
|
||||
// draw table and grid
|
||||
for(sid=0;sid<=nboards*8;sid++) {
|
||||
for(sid=0;sid<=sd['nbrd']*8;sid++) {
|
||||
sn=sid+1;
|
||||
if(sid<nboards*8) w("<div style=\"position:absolute;left:"+(xstart+sid*stwidth-10)+";top:"+(ystart-15)+";width:"+stwidth+";height:20;border:0;padding:0;\"><font size=2>S"+(sn/10>>0)+(sn%10)+"</font></div>");
|
||||
w("<div style=\"position:absolute;left:"+getx(sid)+";top:"+(ystart-10)+";border:1px solid gray;width:0;height:"+(winheight-ystart+30)+";\"></div>");
|
||||
if(sid<sd['nbrd']*8) w("<div style=\"position:absolute;left:"+(xstart+sid*stwidth-10)+"px;top:"+(ystart-15)+"px;width:"+stwidth+"px;height:20px;border:0;padding:0;\"><font size=2>S"+(sn/10>>0)+(sn%10)+"</font></div>");
|
||||
w("<div style=\"position:absolute;left:"+getx(sid)+"px;top:"+(ystart-10)+"px;border:1px solid gray;width:0px;height:"+(winheight-ystart+30)+"px;\"></div>");
|
||||
}
|
||||
// horizontal grid, time
|
||||
for(t=0;t<=24;t++) {
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-15)+";top:"+gety(t*60)+";border:1px solid gray;width:15;height:0;\"></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-8)+";top:"+(gety(t*60)+stheight/2)+";border:1px solid gray;width:8;height:0;\"></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-70)+";top:"+(ystart+t*stheight-7)+";width=70;height:20;border:0;padding:0;\"><font size=2>"+(t/10>>0)+(t%10)+":00</font></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-15)+"px;top:"+gety(t*60)+"px;border:1px solid gray;width:15px;height:0px;\"></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-stwidth/2-8)+"px;top:"+(gety(t*60)+stheight/2)+"px;border:1px solid gray;width:8px;height:0px;\"></div>");
|
||||
w("<div style=\"position:absolute;left:"+(xstart-70)+"px;top:"+(ystart+t*stheight-7)+"px;width=70;height:20px;border:0;padding:0;\"><font size=2>"+(t/10>>0)+(t%10)+":00</font></div>");
|
||||
}
|
||||
plot_currtime();
|
||||
}
|
||||
function draw_program() {
|
||||
// plot program data by a full simulation
|
||||
var simminutes=0,busy=0,match_found=0,bid,s,sid,pid,match=[0,0];
|
||||
var st_array=new Array(nboards*8),pid_array=new Array(nboards*8);
|
||||
var et_array=new Array(nboards*8);
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
var st_array=new Array(sd['nbrd']*8),pid_array=new Array(sd['nbrd']*8);
|
||||
var et_array=new Array(sd['nbrd']*8);
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
st_array[sid]=0;pid_array[sid]=0;et_array[sid]=0;
|
||||
}
|
||||
do { // check through every program
|
||||
|
@ -117,11 +117,11 @@ function draw_program() {
|
|||
for(pid=0;pid<nprogs;pid++) {
|
||||
var prog=pd[pid];
|
||||
if(check_match(prog,simminutes,simdate,simday)) {
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
bid=sid>>3;s=sid%8;
|
||||
if(mas==(sid+1)) continue; // skip master station
|
||||
if(sd['mas']==(sid+1)) continue; // skip master station
|
||||
if(prog[7+bid]&(1<<s)) {
|
||||
et_array[sid]=prog[6]*wl/100>>0;pid_array[sid]=pid+1;
|
||||
et_array[sid]=prog[6]*sd['wl']/100>>0;pid_array[sid]=pid+1;
|
||||
match_found=1;
|
||||
}//if
|
||||
}//for_sid
|
||||
|
@ -129,16 +129,16 @@ function draw_program() {
|
|||
}//for_pid
|
||||
if(match_found) {
|
||||
var acctime=simminutes*60;
|
||||
if(seq) { // sequential
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
if(sd['seq']) { // sequential
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
if(et_array[sid]) {
|
||||
st_array[sid]=acctime;acctime+=et_array[sid];
|
||||
et_array[sid]=acctime;acctime+=sdt;
|
||||
et_array[sid]=acctime;acctime+=sd['sdt'];
|
||||
busy=1;
|
||||
}//if
|
||||
}//for
|
||||
} else {
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
if(et_array[sid]) {
|
||||
st_array[sid]=simminutes*60;
|
||||
et_array[sid]=simminutes*60+et_array[sid];
|
||||
|
@ -149,9 +149,9 @@ function draw_program() {
|
|||
}//if(match_found)
|
||||
if (busy) {
|
||||
var endminutes=run_sched(simminutes*60,st_array,pid_array,et_array)/60>>0;
|
||||
if(seq&&simminutes!=endminutes) simminutes=endminutes;
|
||||
if(sd['seq']&&simminutes!=endminutes) simminutes=endminutes;
|
||||
else simminutes++;
|
||||
for(sid=0;sid<nboards*8;sid++) {st_array[sid]=0;pid_array[sid]=0;et_array[sid]=0;} // clear program data
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {st_array[sid]=0;pid_array[sid]=0;et_array[sid]=0;} // clear program data
|
||||
} else {
|
||||
simminutes++; // increment simulation time
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// print station status
|
||||
function rsn() {
|
||||
var p="";
|
||||
if(!ipas) p=prompt("Please enter your password:","");
|
||||
if(!sd['ipas']) p=prompt("Please enter your password:","");
|
||||
if(p!=null) window.location="/cv?pw="+p+"&rsn=1";
|
||||
}
|
||||
|
||||
|
@ -18,18 +18,18 @@ w("<p><b>Station Status</b>:</p>");
|
|||
w("<table border=1>");
|
||||
var bid,s,sid,sn,rem,remm,rems,off,pname;
|
||||
//off=((en==0||rd!=0||(urs!=0&&rs!=0))?1:0); // move rain stuff to after sid = ...
|
||||
off=((en==0)?1:0);
|
||||
for(bid=0;bid<nbrd;bid++){
|
||||
off=((sd['en']==0)?1:0);
|
||||
for(bid=0;bid<sd['nbrd'];bid++){
|
||||
for(s=0;s<8;s++){
|
||||
w("<tr><td bgcolor=\"#E4E4E4\">");
|
||||
sid=bid*8+s;
|
||||
exempt=((ir[bid]&1<<s)?1:0);
|
||||
if(en==1) {off=(((rd!=0||(urs!=0&&rs!=0))&&exempt!=1)?1:0);}
|
||||
exempt=((sd['ir'][bid]&1<<s)?1:0);
|
||||
if(sd['en']==1) {off=(((sd['rd']!=0||(sd['urs']!=0&&sd['rs']!=0))&&exempt!=1)?1:0);}
|
||||
sn=sid+1;
|
||||
w(snames[sid]+': ');
|
||||
w("</td><td>");
|
||||
if(off) w("<strike>");
|
||||
if(sn==mas) {w(((sbits[bid]>>s)&1?("<b>On</b>").fontcolor("green"):("Off").fontcolor("black"))+" (<b>Master</b>)");}
|
||||
if(sn==sd['mas']) {w(((sbits[bid]>>s)&1?("<b>On</b>").fontcolor("green"):("Off").fontcolor("black"))+" (<b>Master</b>)");}
|
||||
else {
|
||||
rem=ps[sid][1];remm=rem/60>>0;rems=rem%60;
|
||||
pname="P"+ps[sid][0];
|
||||
|
|
|
@ -4,70 +4,79 @@
|
|||
// Creative Commons Attribution ShareAlike 3.0 License
|
||||
// Sep 2012, Rayshobby.net
|
||||
|
||||
var str_tooltips=["Example: GMT-4:00, GMT+5:30 (effective after reboot).", "HTTP port (effective after reboot).", "HTTP port (effective after reboot).", "Number of extension boards", "Sequential running or concurrent running", "Station delay time (in seconds), between 0 and 240.", "Select master station", "Master on delay (in seconds), between +0 and +60.", "Master off delay (in seconds), between -60 and +60.", "Use rain sensor", "Rain sensor type", "Water level, between 0% and 250%.", "Ignore web password"];
|
||||
function w(s) {document.writeln(s);}
|
||||
function imgstr(s) {return "<img src=\""+baseurl+"/static/images/icons/svc_"+s+".png\" height=20 align=absmiddle> ";}
|
||||
function submit_form(f) {
|
||||
// process time zone value
|
||||
var th=parseInt(f.elements["th"].value,10);
|
||||
var tq=parseInt(f.elements["tq"].value,10);
|
||||
tq=(tq/15>>0)/4.0;th=th+(th>=0?tq:-tq);
|
||||
tq=(tq/15>>0)/4.0;
|
||||
th=th+(th>=0?tq:-tq);
|
||||
// huge hack, needs to find a more elegant way
|
||||
f.elements["o1"].value=((th+12)*4)>>0;
|
||||
f.elements["o12"].value=(f.elements["htp"].value)&0xff;
|
||||
f.elements["o13"].value=(f.elements["htp"].value>>8)&0xff;
|
||||
f.elements["o18"].value=f.elements["mas"].value;
|
||||
f.elements["otz"].value=((th+12)*4)>>0;
|
||||
f.elements["ohtp"].value=(f.elements["htp"].value)&0xff;
|
||||
f.elements["ohtp2"].value=(f.elements["htp"].value>>8)&0xff;
|
||||
f.elements["omas"].value=f.elements["mas"].value;
|
||||
f.submit();
|
||||
}
|
||||
function fcancel() {window.location="/";}
|
||||
function fshow() {
|
||||
function ftoggle() {
|
||||
var oid,tip;
|
||||
for(oid=0;oid<nopts;oid++){
|
||||
var state=document.getElementById("tip0").style.display=="none";
|
||||
for(oid=0;oid<opts.length;oid++){
|
||||
tip=document.getElementById("tip"+oid);
|
||||
if(tip!=null) tip.hidden=false;
|
||||
if(tip!=null) tip.style.display=state?"inline":"none";
|
||||
}
|
||||
document.getElementById("tooltips").innerHTML = (state?"Hide Tooltips":"Show Tooltips");
|
||||
}
|
||||
w("<div align=\"center\" style=\"background-color:#EEEEEE;border:2px solid gray;padding:5px 10px;width:240px;border-radius:10px;box-shadow:3px 3px 2px #888888;\">");
|
||||
w("<b>Set Options</b>:<br><font size=2>(Hover on each option to see tooltip)</font></div>");
|
||||
w("<p></p>");
|
||||
w("<button style=\"height:24\" onclick=\"fshow();return false;\">Show Tooltips</button>");
|
||||
w("<button id=\"tooltips\" style=\"height:24\" onclick=\"ftoggle();return false;\">Show Tooltips</button>");
|
||||
// print html form
|
||||
w("<form name=of action=co method=get>");
|
||||
var oid,name,isbool,value,index,pasoid=0;
|
||||
for(oid=0;oid<nopts;oid++){
|
||||
name=opts[oid*4+0];
|
||||
isbool=opts[oid*4+1];
|
||||
value=opts[oid*4+2];
|
||||
index=opts[oid*4+3];
|
||||
if(name=="Ignore password:") pasoid=oid;
|
||||
if(isbool) w("<p title=\""+str_tooltips[oid]+"\"><b>"+name+"</b> <input type=checkbox "+(value>0?"checked":"")+" name=o"+index+">");
|
||||
else {
|
||||
// hack
|
||||
if (name=="Time zone:") {
|
||||
w("<input type=hidden value=0 name=o"+index+">");
|
||||
var oid,label,isbool,value,name,ipasvalue=0;
|
||||
for(oid=0;oid<opts.length;oid++){
|
||||
label=opts[oid][0];
|
||||
datatype=opts[oid][1];
|
||||
value=sd[opts[oid][2]];
|
||||
name=opts[oid][2];
|
||||
tooltip=opts[oid][3];
|
||||
if(name=="ipas") ipasvalue=value;
|
||||
if(datatype == "boolean") {
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <input type=checkbox "+(value>0?"checked":"")+" name=o"+name+">");
|
||||
} else if (datatype == "string") {
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <input type=text size=31 maxlength=31 value='"+value+"' name=o"+name+">");
|
||||
} else {
|
||||
switch (name) {
|
||||
case "tz":
|
||||
w("<input type=hidden value=0 name=o"+name+">");
|
||||
tz=value-48;
|
||||
w("<p title=\""+str_tooltips[oid]+"\"><b>"+name+"</b> GMT<input type=text size=3 maxlength=3 value="+(tz>=0?"+":"-")+(Math.abs(tz)/4>>0)+" name=th>");
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> GMT<input type=text size=3 maxlength=3 value="+(tz>=0?"+":"-")+(Math.abs(tz)/4>>0)+" name=th>");
|
||||
w(":<input type=text size=3 maxlength=3 value="+((Math.abs(tz)%4)*15/10>>0)+((Math.abs(tz)%4)*15%10)+" name=tq>");
|
||||
} else if (name=="Master station:") {
|
||||
w("<input type=hidden value=0 name=o"+index+">");
|
||||
w("<p title=\""+str_tooltips[oid]+"\"><b>"+name+"</b> <select name=mas><option "+(value==0?" selected ":" ")+"value=0>None</option>");
|
||||
break;
|
||||
case "mas":
|
||||
w("<input type=hidden value=0 name=o"+name+">");
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <select name=mas><option "+(value==0?" selected ":" ")+"value=0>None</option>");
|
||||
for(i=1;i<=8;i++) w("<option "+(value==i?" selected ":" ")+"value="+i+">Station 0"+i+"</option>");
|
||||
w("</select>");
|
||||
} else if (name=="HTTP port:") {
|
||||
w("<input type=hidden value=0 name=o"+index+"><input type=hidden value=0 name=o"+(index+1)+">");
|
||||
var port=value+(opts[(oid+1)*4+2]<<8);
|
||||
w("<p title=\""+str_tooltips[oid]+"\"><b>"+name+"</b> <input type=text size=5 maxlength=5 value="+port+" name=htp>");
|
||||
oid++;
|
||||
}
|
||||
else {
|
||||
w("<p title=\""+str_tooltips[oid]+"\"><b>"+name+"</b> <input type=text size=3 maxlength=3 value="+value+" name=o"+index+">");
|
||||
break;
|
||||
case "htp":
|
||||
w("<input type=hidden value=0 name=o"+name+"><input type=hidden value=0 name=o"+name+"2>");
|
||||
var port=value+(opts[(oid+1)][2]<<8);
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <input type=text size=5 maxlength=5 value="+port+" name=ohtp>");
|
||||
break;
|
||||
case "nbrd":
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <input type=text size=3 maxlength=3 value="+(value-1)+" name=o"+name+">");
|
||||
break;
|
||||
default:
|
||||
w("<p title=\""+tooltip+"\"><b>"+label+":</b> <input type=text size=3 maxlength=3 value="+value+" name=o"+name+">");
|
||||
}
|
||||
}
|
||||
//w("</p>");
|
||||
w(" <span style=\"background-color:#FFF2B8;\" id=tip"+oid+" hidden=\"hidden\"><font size=2>"+str_tooltips[oid]+"</font></span></p>");
|
||||
w(" <span style=\"background-color:#FFF2B8;display:none\" id=tip"+oid+"><font size=2>"+tooltip+"</font></span></p>");
|
||||
}
|
||||
w("<p title=\"City name or zip code. Use comma or + in place of space.\"><b>Location:</b> <input type=text maxlength=31 value=\""+loc+"\" name=loc></p>");
|
||||
w("<h4>Password:<input type=password size=10 "+(opts[pasoid*4+2]?"disabled":"")+" name=pw></h4>");
|
||||
w("<h4>Password:<input type=password size=10 "+(ipasvalue?"disabled":"")+" name=pw></h4>");
|
||||
w("<button style=\"height:36\" onclick=\"submit_form(of)\">"+imgstr("submit")+"<b>Submit Changes</b></button>");
|
||||
w("<button style=\"height:36\" onclick=\"fcancel();return false;\">"+imgstr("delall")+"Cancel</button>");
|
||||
w("<h4>Change password</b>:<input type=password size=10 name=npw> Confirm: <input type=password size=10 name=cpw></h4>");
|
||||
|
|
|
@ -9,7 +9,7 @@ function w(s) {document.writeln(s);}
|
|||
function imgstr(s) {return "<img src=\""+baseurl+"/static/images/icons/svc_"+s+".png\" height=20 align=absmiddle> ";}
|
||||
function del(form,idx) {
|
||||
var p="";
|
||||
if(!ipas) p=prompt("Please enter your password:","");
|
||||
if(!sd['ipas']) p=prompt("Please enter your password:","");
|
||||
if(p!=null){form.elements[0].value=p;form.elements[1].value=idx;form.submit();}
|
||||
}
|
||||
function mod(form,idx) {form.elements[0].value=idx;form.submit();}
|
||||
|
@ -38,7 +38,7 @@ function pdays(days){
|
|||
function pstations(data){
|
||||
w("<table border=1 cellpadding=3px>");
|
||||
var bid,s,bits,sid;
|
||||
for(bid=0;bid<nboards;bid++){
|
||||
for(bid=0;bid<sd['nbrd'];bid++){
|
||||
bits=data[bid+7];
|
||||
for(s=0;s<8;s++){
|
||||
sid=bid*8+s;
|
||||
|
@ -61,7 +61,7 @@ w("<button style=\"height:44\" onclick=\"fcancel()\">"+imgstr("back")+"Back</but
|
|||
w("<button style=\"height:44\" onclick=\"mod(mf,-1)\">"+imgstr("addall")+"<b>Add a New Program</b></button>");
|
||||
w("<button style=\"height:44\" onclick=\"del(df,-1)\">"+imgstr("delall")+"Delete All</button>");
|
||||
w("<button style=\"height:44\" onclick=\"fplot()\">"+imgstr("preview")+"Preview</button><hr>");
|
||||
w("<b>Total number of programs: "+nprogs+" (maximum is "+mnp+")</b><br>");
|
||||
w("<b>Total number of programs: "+nprogs+" (maximum is "+sd['mnp']+")</b><br>");
|
||||
// print programs
|
||||
var pid,st,et,iv,du,sd;
|
||||
for(pid=0;pid<nprogs;pid++) {
|
||||
|
|
|
@ -8,17 +8,17 @@ function w(s) {document.writeln(s);}
|
|||
function imgstr(s) {return "<img src=\""+baseurl+"/static/images/icons/svc_"+s+".png\" height=20 align=absmiddle> ";}
|
||||
function rst(f) {
|
||||
var sid,sn;
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
if(sid+1==mas) continue;
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
if(sid+1==sd['mas']) continue;
|
||||
f.elements["mm"+sid].value=0;
|
||||
f.elements["ss"+sid].value=0;
|
||||
}
|
||||
}
|
||||
function fsubmit(f) {
|
||||
var comm="/cr?pw="+(ipas?"":f.elements["pw"].value)+"&t=[";
|
||||
var comm="/cr?pw="+(sd['ipas']?"":f.elements["pw"].value)+"&t=[";
|
||||
var sid,strmm,strss,mm,ss,matchfound=0;
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
if(sid+1==mas) {comm+="0,";continue;}
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
if(sid+1==sd['mas']) {comm+="0,";continue;}
|
||||
strmm=f.elements["mm"+sid].value;
|
||||
strss=f.elements["ss"+sid].value;
|
||||
mm=(strmm=="")?0:parseInt(strmm);
|
||||
|
@ -37,16 +37,16 @@ w("<font size=3><b>Run-Once Program:</b></font></div><p></p>");
|
|||
var sid;
|
||||
w("<table border=1>");
|
||||
w("<form name=rf action=cr method=get>");
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
w("<tr><td bgcolor=\"#E4E4E4\">");
|
||||
w(snames[sid]+": </td><td>");
|
||||
if (sid+1==mas) {w("(<b>Master</b>)<br>");continue;}
|
||||
if (sid+1==sd['mas']) {w("(<b>Master</b>)<br>");continue;}
|
||||
w("<input type=text size=3 maxlength=3 value=0 name=mm"+sid+">:");
|
||||
w("<input type=text size=2 maxlength=2 value=0 name=ss"+sid+"> (mm:ss)<br>");
|
||||
w("</td>");
|
||||
}
|
||||
w("</table>");
|
||||
w("<hr><font size=3><b>Password:</b><input type=password size=10 "+(ipas?"disabled":"")+" name=pw></font><p></p>");
|
||||
w("<hr><font size=3><b>Password:</b><input type=password size=10 "+(sd['ipas']?"disabled":"")+" name=pw></font><p></p>");
|
||||
w("</form></span>");
|
||||
w("<button style=\"height:36\" onclick=\"fsubmit(rf)\">"+imgstr("submit")+"<b>Run Now</b></button>");
|
||||
w("<button style=\"height:36\" onclick=\"rst(rf)\">"+imgstr("reset")+"Reset Time</button>");
|
||||
|
|
|
@ -8,20 +8,20 @@ function w(s) {document.writeln(s);}
|
|||
function imgstr(s) {return "<img src=\""+baseurl+"/static/images/icons/svc_"+s+".png\" height=20 align=absmiddle> ";}
|
||||
function rst() {
|
||||
var sid,sn;
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
sn=sid+1;
|
||||
document.getElementById("n"+sid).value="S"+(sn/10>>0)+(sn%10);
|
||||
}
|
||||
}
|
||||
function fsubmit(f) {
|
||||
if(mas>0) {
|
||||
if(sd['mas']>0) {
|
||||
var s, bid, sid, v;
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
v=0;
|
||||
for(s=0;s<8;s++){
|
||||
sid=bid*8+(7-s);
|
||||
v=v<<1;
|
||||
if(sid+1==mas) {v=v+1;continue;}
|
||||
if(sid+1==sd['mas']) {v=v+1;continue;}
|
||||
if(document.getElementById("mc"+sid).checked) {
|
||||
v=v+1;
|
||||
}
|
||||
|
@ -30,12 +30,12 @@ function fsubmit(f) {
|
|||
}
|
||||
}
|
||||
var vi;
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
vi=0;
|
||||
for(s=0;s<8;s++){
|
||||
sid=bid*8+(7-s);
|
||||
vi=vi<<1;
|
||||
if(sid+1==mas) {vi=vi+1;continue;}
|
||||
if(sid+1==sd['mas']) {vi=vi+1;continue;}
|
||||
if(document.getElementById("rc"+sid).checked) {
|
||||
vi=vi+1;
|
||||
}
|
||||
|
@ -47,27 +47,33 @@ function fsubmit(f) {
|
|||
function fcancel() {window.location="/";}
|
||||
w("<div align=\"center\" style=\"background-color:#EEEEEE;border:2px solid gray;padding:5px 10px;width:240px;border-radius:10px;box-shadow:3px 3px 2px #888888;\">");
|
||||
w("<font size=3><b>Set Stations:</b></font><br>");
|
||||
w("<font size=2>(Maximum name length is "+maxlen+" letters).</font></div><p></p>");
|
||||
w("<font size=2>(Maximum name length is "+sd['snlen']+" letters).</font></div><p></p>");
|
||||
var sid,sn,bid,s;
|
||||
w("<span style=\"line-height:32px\"><form name=sf action=cs method=get>");
|
||||
for(sid=0;sid<nboards*8;sid++) {
|
||||
w("<form name=sf action=cs method=get>");
|
||||
w("<table><tr><th>Station</th><th>Name</th><th>Ignore Rain?</th>" + (sd['mas']>0?"<th>Activate Master?</th>":"") + "</tr>");
|
||||
for(sid=0;sid<sd['nbrd']*8;sid++) {
|
||||
sn=sid+1;
|
||||
bid=sid>>3;
|
||||
s=sid%8;
|
||||
w("Station "+(sn/10>>0)+(sn%10)+":");
|
||||
w("<input type=text size="+maxlen+" maxlength="+maxlen+" value=\""+snames[sid]+"\" name=s"+sid+" id=n"+sid+"> ");
|
||||
if (sid+1!=mas) w("<input type=checkbox "+(rop[bid]&(1<<s)?"checked":"")+" id=rc"+sid+">Ignore rain?");
|
||||
|
||||
if (sid+1==mas) w("(<b>Master</b>)");
|
||||
else if (mas>0) w("<input type=checkbox "+(masop[bid]&(1<<s)?"checked":"")+" id=mc"+sid+">Activate master?");
|
||||
w("<br>");
|
||||
w("<tr><td>"+(sn/10>>0)+(sn%10)+"</td>");
|
||||
if (sid+1==sd['mas']) {
|
||||
w("<td colspan=2>--Master--</td>");
|
||||
} else {
|
||||
w("<td><input type=text size="+sd['snlen']+" maxlength="+sd['snlen']+" value=\""+snames[sid]+"\" name=s"+sid+" id=n"+sid+"></td>");
|
||||
if (sid+1!=sd['mas']) {
|
||||
w("<td><input type=checkbox "+(sd['ir'][bid]&(1<<s)?"checked":"")+" id=rc"+sid+"></td>");
|
||||
}
|
||||
if (sd['mas']>0) w("<td><input type=checkbox "+(sd['mo'][bid]&(1<<s)?"checked":"")+" id=mc"+sid+"></td>");
|
||||
}
|
||||
w("</tr>");
|
||||
}
|
||||
w("<hr><font size=3><b>Password:</b><input type=password size=10 "+(ipas?"disabled":"")+" name=pw></font><p></p>");
|
||||
for(bid=0;bid<nboards;bid++) {
|
||||
w("<input type=hidden name=m"+bid+">");
|
||||
w("</table>");
|
||||
//w("<p>Note: preface a station name with \"~\" to indicate that it is disconnected and hide it in the interface.</p>");
|
||||
w("<hr><font size=3><b>Password:</b><input type=password size=10 "+(sd['ipas']?"disabled":"")+" name=pw></font><p></p>");
|
||||
for(bid=0;bid<sd['nbrd'];bid++) {
|
||||
w("<input type=hidden name=i"+bid+">");
|
||||
}
|
||||
w("</form></span>");
|
||||
w("</form>");
|
||||
w("<button style=\"height:36\" onclick=\"fsubmit(sf)\">"+imgstr("submit")+"<b>Submit Changes</b></button>");
|
||||
w("<button style=\"height:36\" onclick=\"rst()\">"+imgstr("reset")+"Reset Names</button>");
|
||||
w("<button style=\"height:36\" onclick=\"fcancel()\">"+imgstr("delall")+"Cancel</button>");
|
||||
|
|
|
@ -96,10 +96,12 @@ function overlay() {
|
|||
</button>
|
||||
|
||||
$code:
|
||||
if sd['lg'] == 'checked':
|
||||
if sd['lg'] == 1:
|
||||
log_state = "Enabled"
|
||||
log_option = "checked"
|
||||
else:
|
||||
log_state = "Disabled"
|
||||
log_option = ""
|
||||
|
||||
<br><br>
|
||||
Logging $log_state
|
||||
|
@ -119,7 +121,7 @@ $for r in records:
|
|||
<div>
|
||||
<form name="logopts" action="/lo" method="get">
|
||||
<p><h2>Log Options</h2></p>
|
||||
<label for="log">Enable Logging</label> <input type="checkbox" id="log" name="log" $sd['lg'] ><br>
|
||||
<label for="log">Enable Logging</label> <input type="checkbox" id="log" name="log" $log_option ><br>
|
||||
<label for="max">Maximum records to keep:</label> <input type="text" size="4" value="$sd['lr']" id="max" name="nrecords">(0 = no limit)<br>
|
||||
<span id='pwarea' style='display:block'; class="pwspan">
|
||||
<label for="pw">Password Required:</label> <input type="password" size="10"id="pw">
|
||||
|
|
Loading…
Reference in New Issue