Merge Jonathan's 'prototype'

* JM_from_remote:
  Merged options into Dan-in-CA latest version

Conflicts:
	README.md
	ospi.py
	static/scripts/java/svc1.8.3/home.js
This commit is contained in:
Dan-in-CA 2013-10-02 15:57:34 -07:00
commit cdb27826c9
15 changed files with 332 additions and 255 deletions

View File

@ -12,6 +12,14 @@ 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/>

View File

@ -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"/>

18
data/options.txt Normal file
View File

@ -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"]
];

263
ospi.py
View File

@ -1,4 +1,5 @@
#!/usr/bin/python
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.
@ -395,12 +396,16 @@ try:
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]#*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()
@ -491,17 +496,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='+str(gv.ver)+',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')+';</script>\n'
@ -562,15 +577,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
@ -579,82 +587,95 @@ 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.rovals = [0]*(gv.sd['nst']) # Run Once Durations
jsave(gv.sd, 'sd')
return
##<<<<<<< HEAD
## 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.rovals = [0]*(gv.sd['nst']) # Run Once Durations
## jsave(gv.sd, 'sd')
## return
##
##=======
##>>>>>>> JM_from_remote
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):
@ -673,32 +694,52 @@ class change_options:
gv.ps.append([0,0])
gv.rs.append([0,0,0,0])
for i in range(incr):
gv.sbits.append(0)
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)]
gv.sd['ir'] = gv.sd['ir'][:(int(qdict['o15'])+1)]
##<<<<<<< HEAD
## gv.sbits.append(0)
## 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)]
## gv.sd['ir'] = gv.sd['ir'][:(int(qdict['o15'])+1)]
## snames = data('snames')
## nlst = re.findall('[\'"].*?[\'"]', snames)
## nstr = '['+','.join(nlst[:8+(int(qdict['o15'])*8)])+','']'
## save('snames', nstr)
##=======
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)])+','']'
save('snames', nstr)
nstr = '['+','.join(nlst[:8+(onbrd*8)])+','']'
save('snames', nstr)
##>>>>>>> JM_from_remote
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[:int(qdict['o15'])+1]
##<<<<<<< HEAD
## gv.sbits = gv.sbits[:int(qdict['o15'])+1]
## return
##=======
gv.sbits = gv.sbits[:onbrd+1]
return
##>>>>>>> JM_from_remote
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'])+',rop='+str(gv.sd['ir'])+';</script>\n' ## added experimental "Ignore Rain"' feature
##<<<<<<< HEAD
## 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'])+',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'
##>>>>>>> JM_from_remote
stationpg += '<script>snames='+data('snames')+';</script>\n'
stationpg += '<script src=\"'+baseurl()+'/static/scripts/java/svc1.8.3/viewstations.js\"></script>'
return stationpg
@ -775,17 +816,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:
@ -818,11 +857,9 @@ 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
@ -832,11 +869,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
@ -919,15 +953,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
@ -971,10 +1001,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')
@ -994,7 +1024,6 @@ 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(len(p[7:7+gv.sd['nbrd']])): # check each station
for s in range(8):
sid = b*8+s # station index

View File

@ -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

View File

@ -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>&nbsp;";}
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,32 +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+"&deg;"+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()+(((tz-48)>=0)?"+":"-")+(Math.abs(tz-48)/4>>0)+":"+((Math.abs(tz-48)%4)*15/10>>0)+((Math.abs(tz-48)%4)*15%10);
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>");

View File

@ -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]+":&nbsp;&nbsp;</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;

View File

@ -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);}
}

View File

@ -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>&nbsp;");
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>&nbsp;");
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
}

View File

@ -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]+':&nbsp;&nbsp;');
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];

83
static/scripts/java/svc1.8.3/viewoptions.js Normal file → Executable file
View File

@ -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>&nbsp;";}
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>&nbsp;&nbsp;Confirm:&nbsp;<input type=password size=10 name=cpw></h4>");

6
static/scripts/java/svc1.8.3/viewprog.js Normal file → Executable file
View File

@ -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>&nbsp;";}
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++) {

View File

@ -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>&nbsp;";}
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]+":&nbsp;&nbsp;</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>");

46
static/scripts/java/svc1.8.3/viewstations.js Normal file → Executable file
View File

@ -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>&nbsp;";}
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+">&nbsp;");
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>");

View File

@ -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">