From e696101090cd843ecd83c19a1ab77c3380174fe2 Mon Sep 17 00:00:00 2001 From: Angelo V Date: Fri, 12 Jul 2019 22:05:28 +0200 Subject: [PATCH] add interrupt and bug fixes --- HWcontrol.py | 43 +- actuatordbmod.py | 22 +- autofertilizerdbmod.py | 4 + autofertilizermod.py | 30 +- automationdbmod.py | 12 +- automationmod.py | 50 +- autowateringdbmod.py | 12 + autowateringmod.py | 3 +- changelog/change | 26 +- database/default/defautomationdata.txt | 2 +- database/default/definterruptdata.txt | 13 + .../defhwdata-IrrigationHAT-v7.txt | 24 + databasemod.py | 1 - debuggingmod.py | 1 + fertilizerdbmod.py | 4 + filemanagementmod.py | 191 +++++++ flasksettings.py | 2 + hardwaremod.py | 135 +++-- interruptdbmod.py | 303 +++++++++++ interruptmod.py | 372 +++++++++++++ networkmod.py | 44 ++ selectedplanmod.py | 19 +- sensordbmod.py | 27 +- start.py | 396 +++++++++++--- .../filestyle123/bootstrap-filestyle.min.js | 10 + statusdataDBmod.py | 1 - templates/ShowCalibration.html | 221 +++++++- templates/fertilizerplan.html | 29 +- templates/hardwaresetting.html | 56 +- templates/hardwaresettingeditfield.html | 6 +- templates/interrupt.html | 501 ++++++++++++++++++ templates/layout.html | 1 + templates/network.html | 64 ++- templates/networksetting.html | 57 +- templates/setstepper.html | 2 +- templates/showimages.html | 7 +- templates/showsensordata.html | 87 ++- templates/videostream.html | 35 +- templates/wateringplan.html | 12 +- wateringdbmod.py | 7 +- 40 files changed, 2493 insertions(+), 339 deletions(-) create mode 100644 database/default/definterruptdata.txt create mode 100644 database/default/presetHWsetting/defhwdata-IrrigationHAT-v7.txt create mode 100644 filemanagementmod.py create mode 100644 interruptdbmod.py create mode 100644 interruptmod.py create mode 100644 static/filestyle123/bootstrap-filestyle.min.js create mode 100644 templates/interrupt.html diff --git a/HWcontrol.py b/HWcontrol.py index 57d18f3..0215686 100644 --- a/HWcontrol.py +++ b/HWcontrol.py @@ -32,7 +32,7 @@ ISRPI=True -HWCONTROLLIST=["tempsensor","humidsensor","pressuresensor","analogdigital","lightsensor","pulse","readpin","servo","stepper","stepperstatus","photo","mail+info+link","mail+info","returnzero","stoppulse"] +HWCONTROLLIST=["tempsensor","humidsensor","pressuresensor","analogdigital","lightsensor","pulse","pinstate","servo","stepper","stepperstatus","photo","mail+info+link","mail+info","returnzero","stoppulse","interrupt","readinputpin"] RPIMODBGPIOPINLISTPLUS=["I2C", "SPI", "2", "3", "4","5","6", "7", "8", "9", "10", "11", "12","13","14", "15", "16","17", "18", "19", "20","21","22", "23", "24", "25","26", "27", "N/A","V1","V2","V3","V4","V5","V6","V7","V8"] RPIMODBGPIOPINLIST=["2", "3", "4","5","6", "7", "8", "9", "10", "11", "12","13","14", "15", "16","17", "18", "19", "20","21","22", "23", "24", "25","26", "27","N/A"] ADCCHANNELLIST=["0","1","2","3","4","5","6","7", "N/A"] #MCP3008 chip has 8 input channels @@ -141,6 +141,9 @@ def execute_task(cmd, message, recdata): elif cmd==HWCONTROLLIST[14]: # stoppulse return gpio_stoppulse(cmd, message, recdata) + elif cmd==HWCONTROLLIST[16]: # readinputpin + return read_input_pin(cmd, message, recdata) + else: print "Command not found" @@ -364,7 +367,7 @@ def get_MCP3008_channel(cmd, message, recdata): MCP3008_busy_flag=True - powerPIN_start(POWERPIN,"pos",0.05) + powerPIN_start(POWERPIN,"pos",0) refvoltage=5.0 @@ -383,7 +386,7 @@ def get_MCP3008_channel(cmd, message, recdata): dataarray=[] print "Starting sample reading" - for x in range(0, 39): + for x in range(0, 29): #number of samples # read data from selected channel adc = spi.xfer2([1,(8+channel)<<4,0]) @@ -517,6 +520,7 @@ def endpulse(PIN,logic,POWERPIN): def gpio_pulse(cmd, message, recdata): + successflag=0 msgarray=message.split(":") messagelen=len(msgarray) PIN=int(msgarray[1]) @@ -550,8 +554,10 @@ def gpio_pulse(cmd, message, recdata): GPIO_data[PIN]["threadID"] = threading.Timer(pulsesecond, endpulse, [PIN , logic , POWERPIN]) GPIO_data[PIN]["threadID"].start() print "pulse started", time.ctime() , " PIN=", PIN , " Logic=", logic + successflag=1 recdata.append(cmd) recdata.append(PIN) + recdata.append(successflag) return True def gpio_stoppulse(cmd, message, recdata): @@ -590,6 +596,15 @@ def gpio_pin_level(cmd, message, recdata): recdata.append("e") return False +def read_input_pin(cmd, message, recdata): + successflag=1 + msgarray=message.split(":") + PIN=int(msgarray[0]) + recdata.append(cmd) + recdata.append(str(GPIO.input(PIN))) + recdata.append(successflag) + return True + def gpio_set_servo(cmd, message, recdata): @@ -632,18 +647,16 @@ def gpio_set_stepper(cmd, message, recdata , stepper_data): speed=int(msgarray[3]) steps=int(msgarray[4]) - waitstep=0.1 - waittime=0 - maxwait=2.5 - while (read_status_data(stepper_data,Interface,"busyflag")==True)and(waittime ", waittime - if (waittime>=maxwait): - #something wrog, wait too long, avoid initiate further processing + if read_status_data(stepper_data,Interface,"busyflag"): # check how long the busyflag has been True lasttime=read_status_data(stepper_data,Interface,"busyflagtime") deltat=datetime.datetime.utcnow()-lasttime @@ -655,8 +668,8 @@ def gpio_set_stepper(cmd, message, recdata , stepper_data): mh = Adafruit_MotorHAT() mh.reset() else: - print "Stepper wait time EXCEEDED " - logger.warning("Stepper Wait Time exceeded, not proceeding with stepper: %s", Interface) + print "Stepper busy " + logger.warning("Stepper Busy, not proceeding with stepper: %s", Interface) return False write_status_data(stepper_data,Interface,"busyflag",True) diff --git a/actuatordbmod.py b/actuatordbmod.py index e1528d7..7dfdc24 100644 --- a/actuatordbmod.py +++ b/actuatordbmod.py @@ -113,6 +113,7 @@ def getAllActuatorDataPeriodv2(enddate,pastdays): num = int(pastdays) tdelta=timedelta(days=num) startdate=enddate-tdelta + print " actuatordbmod" print " stratdate " ,startdate print " enddate ", enddate outputallsensordata=[] @@ -163,12 +164,12 @@ def RemoveActuatorDataPeriod(removebeforedays): # sensor data -------------------------------------------- - - + def EvaluateDataPeriod(sensordata,startdate,enddate): # sensor data -------------------------------------------- + isok=False outputdata={} summa=0 inde=0 @@ -188,11 +189,12 @@ def EvaluateDataPeriod(sensordata,startdate,enddate): summa=summa+number inde=inde+1 except ValueError: - print "Error in database reading ",dateref , " " ,data[1] + print "Evaluation : Error in database reading ",dateref , " " ,data[1] if inde>0: average=summa/inde + isok=True else: average=0 mini=0 @@ -202,9 +204,15 @@ def EvaluateDataPeriod(sensordata,startdate,enddate): outputdata["average"]=average outputdata["min"]=mini outputdata["max"]=maxi - return outputdata - - + return isok , outputdata + + + + + + + + def SumProductDataPeriod(sensordata,startdate,enddate,timeinterval): # sensor data -------------------------------------------- @@ -256,7 +264,7 @@ def sensorsysinfomatrix(): starttime= endtime - timedelta(days=1) data=[] getActuatordbdata(name,data) - evaluateddata=EvaluateDataPeriod(data,starttime,endtime) #set date interval for average + isok, evaluateddata=EvaluateDataPeriod(data,starttime,endtime) #set date interval for average row.append(str('%.1f' % (evaluateddata["sum"]))) diff --git a/autofertilizerdbmod.py b/autofertilizerdbmod.py index dc33769..67d9983 100644 --- a/autofertilizerdbmod.py +++ b/autofertilizerdbmod.py @@ -49,6 +49,10 @@ # filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue) # filestoragemod.deletefile(filename) +def readfromfile(): + global WTdata + filestoragemod.readfiledata(WTDATAFILENAME,WTdata) + def consistencycheck(): diff --git a/autofertilizermod.py b/autofertilizermod.py index 8197beb..6deb50a 100644 --- a/autofertilizermod.py +++ b/autofertilizermod.py @@ -9,14 +9,16 @@ import sensordbmod import actuatordbmod import fertilizerdbmod +import statusdataDBmod logger = logging.getLogger("hydrosys4."+__name__) # status array, required to check the ongoing actions within a watering cycle elementlist= autofertilizerdbmod.getelementlist() AUTO_data={} # dictionary of dictionary -for element in elementlist: - AUTO_data[element]={"triggerdate":datetime.utcnow(),"tobeactivated":False, "duration":0, "alertcounter":0} +#for element in elementlist: +# AUTO_data[element]={"triggerdate":datetime.utcnow(),"tobeactivated":False, "duration":0, "alertcounter":0} +AUTO_data["default"]={"triggerdate":datetime.utcnow(),"tobeactivated":False, "duration":0, "alertcounter":0} # triggerdate, datetime when the doser have been triggered to start # tobeactivated, doser need to be activated in the next opportunity @@ -48,25 +50,31 @@ def checkactivate(elementwater,durationwater): print " Check Water duration ", durationwater ,">", minwaterduration if durationwater>minwaterduration: # watering time above the set threshold print " OK Water duration " - if AUTO_data[element]["tobeactivated"]: #if flag is ON + if statusdataDBmod.read_status_data(AUTO_data,element,"tobeactivated"): #if flag is ON print " Activate ", element - durationfer=AUTO_data[element]["duration"] + durationfer=statusdataDBmod.read_status_data(AUTO_data,element,"duration") activatedoser(element,durationfer) time.sleep(durationfer) #this blocks the system (and watering activation) for n seconds ... not best practice else: print " No pending request to activate ", element -def activatedoser(target, duration): - print target, " ",duration, " " , datetime.now() +def activatedoser(element, duration): + print element, " ",duration, " " , datetime.now() logger.info('Doser Pulse, pulse time for ms = %s', duration) - pulseok=hardwaremod.makepulse(target,duration) + pulseok=hardwaremod.makepulse(element,duration) # salva su database - actuatordbmod.insertdataintable(target,duration) + actuatordbmod.insertdataintable(element,duration) # put flag down global AUTO_data - AUTO_data[target]["tobeactivated"]=False - AUTO_data[target]["duration"]=0 - AUTO_data[target]["triggerdate"]=datetime.now() + statusdataDBmod.write_status_data(AUTO_data,element,"tobeactivated",False) + statusdataDBmod.write_status_data(AUTO_data,element,"duration",0) + statusdataDBmod.write_status_data(AUTO_data,element,"triggerdate",datetime.now()) + +def setActivationDurationDate(element,tobeactivated,duration,triggerdate): + global AUTO_data + statusdataDBmod.write_status_data(AUTO_data,element,"tobeactivated",tobeactivated) #true or false + statusdataDBmod.write_status_data(AUTO_data,element,"duration",duration) + statusdataDBmod.write_status_data(AUTO_data,element,"triggerdate",triggerdate) def checkworkmode(element): diff --git a/automationdbmod.py b/automationdbmod.py index d9b9b4d..2ed49a1 100644 --- a/automationdbmod.py +++ b/automationdbmod.py @@ -49,6 +49,10 @@ # filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue) # filestoragemod.deletefile(filename) +def readfromfile(): + global WTdata + filestoragemod.readfiledata(WTDATAFILENAME,WTdata) + def consistencycheck(): @@ -149,7 +153,13 @@ def getelementlist(): return datalist def sensorlist(): - tablelist=hardwaremod.searchdatalist(hardwaremod.HW_INFO_IOTYPE,"input",hardwaremod.HW_INFO_NAME) + tablelisttemp=hardwaremod.searchdatalist(hardwaremod.HW_INFO_IOTYPE,"input",hardwaremod.HW_INFO_NAME) + # exclude the event input + inputeventlist=hardwaremod.searchdatalist(hardwaremod.HW_CTRL_CMD,"interrupt",hardwaremod.HW_INFO_NAME) + tablelist=[] + for element in tablelisttemp: + if not element in inputeventlist: + tablelist.append(element) return tablelist def sensorlisttriggertime(): diff --git a/automationmod.py b/automationmod.py index 0cef522..eab5814 100644 --- a/automationmod.py +++ b/automationmod.py @@ -17,21 +17,21 @@ # status array, required to check the ongoing actions elementlist= automationdbmod.getelementlist() AUTO_data={} # dictionary of dictionary -AUTO_data["default"]={"lastactiontime":datetime.now(),"actionvalue":0, "alertcounter":0, "infocounter":0, "status":"ok"} +AUTO_data["default"]={"lastactiontime":datetime.utcnow(),"actionvalue":0, "alertcounter":0, "infocounter":0, "status":"ok"} def cyclereset(element): global AUTO_data waitingtime=hardwaremod.toint(automationdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),0) - AUTO_data[element]={"lastactiontime":datetime.now() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} + AUTO_data[element]={"lastactiontime":datetime.utcnow() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} def cycleresetall(): global AUTO_data elementlist= automationdbmod.getelementlist() for element in elementlist: waitingtime=hardwaremod.toint(automationdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),0) - AUTO_data[element]={"lastactiontime":datetime.now() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} + AUTO_data[element]={"lastactiontime":datetime.utcnow() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} def automationcheck(refsensor): @@ -68,15 +68,10 @@ def automationexecute(refsensor,element): actuatormaxthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[1],0) actuatorminthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[0],actuatormaxthreshold) - # evaluate variables for operational period check - now = datetime.now() - nowtime = now.time() - starttimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[0],0) - starttimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[1],0) - endtimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[0],1) - endtimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[1],0) - starttime=time(starttimeh,starttimem) - endtime=time(endtimeh,endtimem) + # evaluate variables for operational period check + + starttime = datetime.strptime(automationdbmod.searchdata("element",element,"allowedperiod")[0], '%H:%M').time() + endtime = datetime.strptime(automationdbmod.searchdata("element",element,"allowedperiod")[1], '%H:%M').time() # get other parameters maxstepnumber=hardwaremod.toint(automationdbmod.searchdata("element",element,"stepnumber"),1) @@ -117,7 +112,7 @@ def automationexecute(refsensor,element): # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) - timeok=isNowInTimePeriod(starttime, endtime, nowtime) + timeok=isNowInTimePeriod(starttime, endtime, datetime.now().time()) # don't use UTC here! print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime if timeok: logger.info('inside allowed time') @@ -189,8 +184,10 @@ def automationexecute(refsensor,element): # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) # END MAIN ALGORITHM - Reverse + else: + logger.error('No valid calculation operation on the stored sensor data') else: - logger.info('No valid calculation operation on the stored sensor data') + logger.info('Outside allowed Time, Stop') elif workmode=="Emergency Activation": print "Emergency Activation" @@ -235,8 +232,8 @@ def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) lastactiontime=statusdataDBmod.read_status_data(AUTO_data,element,"lastactiontime") - print ' Previous action: ' , lastactiontime , ' Now: ', datetime.now() - timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.now()) + print ' Previous action: ' , lastactiontime , ' Now: ', datetime.utcnow() + timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.utcnow()) print 'Time interval between actions', timedifference ,'. threshold', waitingtime logger.info('Time interval between Actions %d threshold %d', timedifference,waitingtime) if timedifference>=waitingtime: # sufficient time between actions @@ -252,7 +249,7 @@ def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): textmessage="INFO: " + sensor + " value " + str(sensorvalue) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: - statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.now()) + statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) else: @@ -292,10 +289,11 @@ def activateactuator(target, value): # return true in case the state change: ac def isNowInTimePeriod(startTime, endTime, nowTime): - if startTime < endTime: - return nowTime >= startTime and nowTime <= endTime - else: #Over midnight - return nowTime >= startTime or nowTime <= endTime + print startTime," ", endTime," " , nowTime + if startTime < endTime: + return nowTime >= startTime and nowTime <= endTime + else: #Over midnight + return nowTime >= startTime or nowTime <= endTime def sensorreading(sensorname,MinutesOfAverage,operation): @@ -314,9 +312,13 @@ def sensorreading(sensorname,MinutesOfAverage,operation): if samplesnumber>0: sensordata=[] sensordbmod.getsensordbdatasamplesN(sensorname,sensordata,samplesnumber) - starttimecalc=datetime.now()-timedelta(minutes=(MinutesOfAverage+theinterval)) #if Minutes of average is zero, it allows to have at least one sample - quantity=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now())[operation] - isok=True + datenow=datetime.now() # dont put UTC here !!! + starttimecalc=datenow-timedelta(minutes=(MinutesOfAverage+theinterval)) #if Minutes of average is zero, it allows to have at least one sample + isok, quantitylist=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datenow) + quantity=quantitylist[operation] + # sensor reading value + logger.info('Sensor reading <%s>=<%s>',sensorname,str(quantity)) + print "sensor Reading ", sensorname, "=" , quantity return isok , quantity diff --git a/autowateringdbmod.py b/autowateringdbmod.py index 72e8dea..34b955a 100644 --- a/autowateringdbmod.py +++ b/autowateringdbmod.py @@ -49,6 +49,9 @@ # filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue) # filestoragemod.deletefile(filename) +def readfromfile(): + global WTdata + filestoragemod.readfiledata(WTDATAFILENAME,WTdata) def consistencycheck(): @@ -148,6 +151,15 @@ def gethygrosensorfromactuator(actuatorname): else: return "" +def checkactivehygrosensor(sensorname): + recordkey="sensor" + recordvalue=sensorname + keytosearch="workmode" + workmode=searchdata(recordkey,recordvalue,keytosearch) + if workmode!="": #if result is "" then the item has not been found + if workmode!="None": + return True + return False diff --git a/autowateringmod.py b/autowateringmod.py index de206fc..7215a5d 100644 --- a/autowateringmod.py +++ b/autowateringmod.py @@ -583,7 +583,8 @@ def sensorreading(sensorname): sensordbmod.getsensordbdatasamplesN(sensorname,sensordata,samplesnumber) # still necessary to filter the sample based on timestamp, due to the possibility of missing samples starttimecalc=datetime.now()-timedelta(minutes=int(MinutesOfAverage)) - quantity=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now())["max"] + isok, quantitylist=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now()) + quantity=quantitylist["max"] return quantity def lastsensorreading(sensorname): diff --git a/changelog/change b/changelog/change index 575b706..0eb82d1 100644 --- a/changelog/change +++ b/changelog/change @@ -288,22 +288,44 @@ sensordata, added non paired hygrometers in hygrometer chart Added Minutes in the watering plan interface -homepage, added the used for for others use +homepage, added the used for for others use than watering and fertilizer +2019-06-12 -> release 101 +Add the interrupt page & function +Fixed bug in the Hardwaresetting when edit table - Addrow now fixed +2019-07-12 -> release 105a +fixed bug in "setting" name change +fixed minor bug when using underscore in names + +fixed video page error when the servo not present in HW list + +Added download configuration button + +Added upload configuration (still to be tested properly) + + + + + + +NOTE: +So that meant using RPIO for PWM (DMA) and GPIO for GPIO. Luckily a little bit of hackery made that easy: + +import RPIO.PWM as PWM +import RPi.GPIO as RPIO ------- Future releases: ----------- -fix the test photo in setting, sometimes the servo does not move enable HTTPS, not public version diff --git a/database/default/defautomationdata.txt b/database/default/defautomationdata.txt index 58c7e51..38dedea 100644 --- a/database/default/defautomationdata.txt +++ b/database/default/defautomationdata.txt @@ -1 +1 @@ -{"element": "", "sensor_threshold": ["2.0", "4.0"],"workmode": "None","sensor": "","stepnumber": "0","allowedperiod": ["21:00","05:00"], "pausebetweenwtstepsmin":"45", "averagesample":"2", "mailalerttype":"warningonly" , "actuator_threshold": ["0.0", "0.0"] ,"mathoperation":"average" } +{"element": "", "sensor_threshold": ["2.0", "4.0"],"workmode": "None","sensor": "","stepnumber": "1","allowedperiod": ["00:00","00:00"], "pausebetweenwtstepsmin":"45", "averagesample":"2", "mailalerttype":"warningonly" , "actuator_threshold": ["0.0", "0.0"] ,"mathoperation":"average" } diff --git a/database/default/definterruptdata.txt b/database/default/definterruptdata.txt new file mode 100644 index 0000000..a9660df --- /dev/null +++ b/database/default/definterruptdata.txt @@ -0,0 +1,13 @@ +{"element": "", "workmode":"None" , "sensor":"" , "sensor_mode":"Edge", "actuator_output":"", "preemptive_period":"1", "actionmode_afterfirst":"None", "folloup_output":"", "allowedperiod": ["00:00","00:00"] , "mailalerttype":"None"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water1", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt1", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water2", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt2", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water3", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt3", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water4", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt4", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water5", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt5", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water6", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt6", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water7", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt7", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "Remove and Follow-up", "actuator_output": "50", "allowedperiod": ["00:00", "00:00"], "element": "water8", "folloup_output": "1", "mailalerttype": "None", "preemptive_period": "1", "sensor": "Interrupt8", "sensor_mode": "Edge + Level", "workmode": "Pre-emptive Blocking"} +{"actionmode_afterfirst": "None", "actuator_output": "", "allowedperiod": ["00:00", "00:00"], "element": "mail1", "folloup_output": "", "mailalerttype": "None", "preemptive_period": "1", "sensor": "", "sensor_mode": "Rising Edge", "workmode": "None"} +{"actionmode_afterfirst": "None", "actuator_output": "", "allowedperiod": ["00:00", "00:00"], "element": "mail2", "folloup_output": "", "mailalerttype": "None", "preemptive_period": "1", "sensor": "", "sensor_mode": "Rising Edge", "workmode": "None"} +{"actionmode_afterfirst": "None", "actuator_output": "", "allowedperiod": ["00:00", "00:00"], "element": "photo", "folloup_output": "", "mailalerttype": "None", "preemptive_period": "1", "sensor": "", "sensor_mode": "Rising Edge", "workmode": "None"} +{"actionmode_afterfirst": "None", "actuator_output": "", "allowedperiod": ["00:00", "00:00"], "element": "servo1", "folloup_output": "", "mailalerttype": "None", "preemptive_period": "1", "sensor": "", "sensor_mode": "Edge", "workmode": "None"} diff --git a/database/default/presetHWsetting/defhwdata-IrrigationHAT-v7.txt b/database/default/presetHWsetting/defhwdata-IrrigationHAT-v7.txt new file mode 100644 index 0000000..ae6f0f2 --- /dev/null +++ b/database/default/presetHWsetting/defhwdata-IrrigationHAT-v7.txt @@ -0,0 +1,24 @@ +{"IOtype": "input" ,"name": "tempsensor1", "unit" : "C", "measure":"Temperature", "controllercmd": "tempsensor", "pin": "24" , "usefor" : "temperaturecontrol", "schedulingtype":"periodic", "time":"00:15:05"} +{"IOtype": "input" ,"name": "humidsensor1", "unit" : "%", "measure":"Humidity", "controllercmd": "humidsensor", "pin": "24" , "usefor" : "humiditycontrol", "schedulingtype":"periodic", "time":"00:15:03"} +{"IOtype": "input" ,"name": "lightsensor1", "unit" : "Lum", "measure":"Light", "controllercmd": "lightsensor", "pin": "I2C" , "usefor" : "lightcontrol", "schedulingtype":"periodic", "time":"00:15:01"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water1", "pin": "20", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water2", "pin": "26", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water3", "pin": "16", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water4", "pin": "19", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water5", "pin": "13", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water6", "pin": "12", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water7", "pin": "6", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" , "controllercmd": "pulse", "logic": "neg", "name": "water8", "pin": "5", "usefor": "watercontrol", "measure": "Time" , "unit" : "sec", "schedulingtype":"oneshot"} +{"IOtype": "output" ,"usefor": "mailcontrol", "address": "", "controllercmd": "mail+info+link","name": "mail1", "time": "10:00", "title": "Hydrosys today report", "measure" : "Mail" , "unit" : "pcs" , "schedulingtype":"oneshot"} +{"IOtype": "output" ,"usefor": "mailcontrol", "address": "", "controllercmd": "mail+info","name": "mail2", "time": "10:00", "title": "Hydrosys today report", "measure" : "Mail" , "unit" : "pcs" , "schedulingtype":"oneshot"} +{"IOtype": "output" ,"usefor": "photocontrol", "controllercmd": "photo", "name": "photo", "time": "09:30", "measure" : "Photo" , "unit" : "pcs", "schedulingtype":"oneshot"} +{"ADCchannel": "0", "IOtype": "output", "controllercmd": "servo", "frequency": "50", "logic": "pos", "address": "", "title": "", "max": "12", "measure": "Percentage", "min": "2", "name": "servo1", "pin": "21", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "", "unit": "C", "usefor": "N/A"} +{"IOtype": "input" ,"name": "TimeTrigger", "unit" : "%", "measure":"Time", "controllercmd": "returnzero", "pin": "N/A" , "usefor" : "N/A", "schedulingtype":"periodic", "time":"00:05:00"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt1", "pin": "14", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt2", "pin": "4", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt3", "pin": "15", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt4", "pin": "18", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt5", "pin": "17", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt6", "pin": "27", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt7", "pin": "23", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} +{"ADCchannel": "N/A", "IOtype": "input", "address": "", "controllercmd": "interrupt", "frequency": "", "logic": "pos", "max": "", "measure": "Events", "min": "", "name": "Interrupt8", "pin": "22", "powerpin": "N/A", "schedulingtype": "oneshot", "time": "00:00:00", "title": "", "unit": "Pcs", "usefor": "sensorquery"} diff --git a/databasemod.py b/databasemod.py index c4861a0..123fd7e 100644 --- a/databasemod.py +++ b/databasemod.py @@ -188,7 +188,6 @@ def getdatafromfieldslimit(filename,table,fieldlist,valuelist,limit): db.close() - def deleterowwithfield(filename,table,field,value): print "delete field ", field , " with value ", value diff --git a/debuggingmod.py b/debuggingmod.py index 9fd2279..3df6792 100644 --- a/debuggingmod.py +++ b/debuggingmod.py @@ -34,6 +34,7 @@ def searchsyslogkeyword(keyword): return extract def searchLOGkeyword(filename,keyword): + print "debugging check errors in: ", filename rownumber="300" data=tailLOGcmd(filename,rownumber) numrowafter=10 diff --git a/fertilizerdbmod.py b/fertilizerdbmod.py index 76cb1b4..c3bcf92 100644 --- a/fertilizerdbmod.py +++ b/fertilizerdbmod.py @@ -49,6 +49,10 @@ # filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue) # filestoragemod.deletefile(filename) +def readfromfile(): + global FTdata + filestoragemod.readfiledata(FTDATAFILENAME,FTdata) + def consitencycheck(): diff --git a/filemanagementmod.py b/filemanagementmod.py new file mode 100644 index 0000000..480f4ce --- /dev/null +++ b/filemanagementmod.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- + +import shutil +import logging +import re +import os +import os.path +import sys +import string +from datetime import datetime,date,timedelta +import filestoragemod +import copy + + +# ///////////////// -- GLOBAL VARIABLES AND INIZIALIZATION --- ////////////////////////////////////////// + +DATABASEPATH=filestoragemod.DATABASEPATH # by default this variable is "database" +CONFIGDOWNLOADPATH="download/configdownload" +ZIPCONFIGDOWNLOADPATH="download/zipconfig" +logger = logging.getLogger("hydrosys4."+__name__) + + + + +def folderfilelist(basefolder, folder , filetype): + + folderpath=os.path.join(basefolder, folder) #database path + + # control if the folder exist otherwise create it + if not os.path.exists(folderpath): + os.makedirs(folderpath) + print " folder has been created" + + filelist=[] + sortedlist=sorted([f for f in os.listdir(folderpath) if os.path.isfile(os.path.join(folderpath, f))]) + sortedlist.reverse() + + # select file with given extension" + for files in sortedlist: + if (files.endswith(filetype)): + tempdict={} + tempdict["filename"]=files + tempdict["relativepath"]=folder + filelist.append(tempdict) + + return filelist + +def copyfiles(basefolder, filelist, relativedstfolder): + for filedata in filelist: + fullsrcfolder=os.path.join(basefolder, filedata["relativepath"]) + src=os.path.join(fullsrcfolder, filedata["filename"]) + dstfilename=filedata["filename"] + fulldstfolder=os.path.join(basefolder, relativedstfolder) + dst=os.path.join(fulldstfolder, dstfilename) + print "COPY, source = " , src, "destination =" , dst + try: + shutil.copyfile(src, dst) + answer="ready" + except: + answer="problem copying file" + + +def deletefilesinfolder(basefolder, relativefolder): + fullfolderpath=os.path.join(basefolder, relativefolder) + # control if the folder exist otherwise create it + if not os.path.exists(fullfolderpath): + os.makedirs(fullfolderpath) + print " folder has been created" + return 0 + + sortedlist=os.listdir(fullfolderpath) + i=0 + for files in sortedlist: + filenamepath=os.path.join(fullfolderpath, files) + if os.path.isfile(filenamepath): + os.remove(filenamepath) + i=i+1 + return i + + + + +def zipfolder(basefolder, relativefolder, zipfilename , relativezipfolder): + fullfolderpath=os.path.join(basefolder, relativefolder) + zipfullpath=os.path.join(basefolder, relativezipfolder) + zipfilenamepath=os.path.join(zipfullpath, zipfilename) + if os.path.exists(fullfolderpath): + shutil.make_archive(zipfilenamepath, 'zip', fullfolderpath) + return zipfilenamepath+".zip" + + +def unzipfolder(basefolder, relativefolder, zipfilename , absolutezipfolder): + fullfolderpath=os.path.join(basefolder, relativefolder) + zipfullpath=absolutezipfolder + zipfilename=zipfilename+".zip" + zipfilenamepath=os.path.join(zipfullpath, zipfilename) + + # control if the folder exist otherwise create it + if not os.path.exists(fullfolderpath): + os.makedirs(fullfolderpath) + print " folder has been created" + print "unzip file=" , zipfilenamepath + if os.path.isfile(zipfilenamepath): + # unzipping + + #shutil.unpack_archive(zipfilenamepath, fullfolderpath , "zip") available in python 2.7.6, but default stretch has the 2.7.13 + import zipfile + zip_ref = zipfile.ZipFile(zipfilenamepath, 'r') + zip_ref.extractall(fullfolderpath) + zip_ref.close() + + return + + + +def configfilezip(): + basefolder=get_path() + relativedstfolder=os.path.join("static", CONFIGDOWNLOADPATH) + relativezipfolder=os.path.join("static", ZIPCONFIGDOWNLOADPATH) + #delete files in download folder, or create it if not existing + deletefilesinfolder(basefolder, relativedstfolder) + #get config files list + relativeconfigfolder=DATABASEPATH + filedatalist=folderfilelist(basefolder, relativeconfigfolder , ".txt") + #copy config files in the folder + copyfiles(basefolder, filedatalist, relativedstfolder) + # make zip file and get link + zipfilename="allconfigfiles" + zipfilenamepath=zipfolder(basefolder, relativedstfolder, zipfilename , relativezipfolder) + # check file exist + if os.path.isfile(zipfilenamepath): + filelink=ZIPCONFIGDOWNLOADPATH+"/"+zipfilename+".zip" # relative path vithout static + else: + filelink="" + print filelink + return filelink + +def configfileunzip(): + basefolder=get_path() + relativedstfolder=os.path.join("static", CONFIGDOWNLOADPATH) + relativezipfolder=os.path.join("static", ZIPCONFIGDOWNLOADPATH) + #delete files in download folder, or create it if not existing + deletefilesinfolder(basefolder, relativedstfolder) + # make unzip zip file and get link + zipfilename="allconfigfiles" + unzipfolder(basefolder, relativedstfolder, zipfilename , relativezipfolder) + filelink=ZIPCONFIGDOWNLOADPATH+"/"+zipfilename # relative path vithout static + print filelink + return filelink + +def restoreconfigfilefromzip(absolutezipfolder): + basefolder=get_path() + relativedstfolder=os.path.join("static", CONFIGDOWNLOADPATH) + #delete files in download folder, or create it if not existing + deletefilesinfolder(basefolder, relativedstfolder) + # make unzip zip file and get link + zipfilename="allconfigfiles" + unzipfolder(basefolder, relativedstfolder, zipfilename , absolutezipfolder) + #get config files list + relativeconfigfolder=relativedstfolder + filedatalist=folderfilelist(basefolder, relativeconfigfolder , ".txt") + #copy config files in the folder + relativedstfolder=DATABASEPATH + copyfiles(basefolder, filedatalist, relativedstfolder) + + + + +def get_path(): + '''Get the path to this script no matter how it's run.''' + #Determine if the application is a py/pyw or a frozen exe. + if hasattr(sys, 'frozen'): + # If run from exe + dir_path = os.path.dirname(sys.executable) + elif '__file__' in locals(): + # If run from py + dir_path = os.path.dirname(__file__) + else: + # If run from command line + dir_path = sys.path[0] + return dir_path + + + + +if __name__ == '__main__': + # comment + print "test copy and zip" + configfileunzip() + #restoreconfigfilefromzip() + diff --git a/flasksettings.py b/flasksettings.py index 34f008d..655c69e 100644 --- a/flasksettings.py +++ b/flasksettings.py @@ -1,2 +1,4 @@ # configuration SECRET_KEY = 'thisisnotsafe' +UPLOAD_FOLDER = "static/upload" +MAX_CONTENT_LENGTH = 1048576 diff --git a/hardwaremod.py b/hardwaremod.py index c73fd52..0fe1142 100644 --- a/hardwaremod.py +++ b/hardwaremod.py @@ -67,7 +67,7 @@ HW_FUNC_TIME="time" #function group , optional, description of time or interval to activate the item depending on the "schedulingtype" item, in case of interval information the minutes are used for the period, seconds are used for start offset USAGELIST=["sensorquery", "watercontrol", "fertilizercontrol", "lightcontrol", "temperaturecontrol", "humiditycontrol", "photocontrol", "mailcontrol", "powercontrol", "N/A", "Other"] -MEASURELIST=["Temperature", "Humidity" , "Light" , "Pressure" , "Time", "Quantity", "Moisture","Percentage"] +MEASURELIST=["Temperature", "Humidity" , "Light" , "Pressure" , "Time", "Quantity", "Moisture","Percentage","Events"] MEASUREUNITLIST=["C", "%" , "Lum" , "hPa" , "Sec", "Pcs", "Volt","F"] @@ -115,9 +115,13 @@ Stepper_Status={} Stepper_Status["default"]={'position':"0"} +Blocking_Status={} +Blocking_Status["default"]={'priority':0} # priority level, the commands are executed only if the command priority is higher or equlal to the blocking status priority + + def read_status_data(data,element,variable): - print data + #print data if element in data: print " element present" elementdata=data[element] @@ -232,8 +236,21 @@ def checkdata(fieldtocheck,dictdata,temp=True): # check if basic info in the fie #dictdata[HW_FUNC_SCHEDTYPE]=["oneshot", "periodic"] #scheduling type return True, "" -def sendcommand(cmd,sendstring,recdata): - return HWcontrol.sendcommand(cmd,sendstring,recdata) +def sendcommand(cmd,sendstring,recdata,target="", priority=0): + if target!="": + prioritystatus=read_status_data(Blocking_Status,target,'priority') + #print " Target output ", target , "priority status: ", prioritystatus , " Command Priority: ", priority + #check if the actions are blocked + if priority>=prioritystatus: + return HWcontrol.sendcommand(cmd,sendstring,recdata) + else: + successflag=0 + recdata.append(cmd) + recdata.append("blocked") + recdata.append(successflag) + return True + else: + return HWcontrol.sendcommand(cmd,sendstring,recdata) def getsensordata(sensorname,attemptnumber): #needed @@ -251,7 +268,7 @@ def getsensordata(sensorname,attemptnumber): #needed ack=False i=0 while (not ack)and(i0: - out , isdone=GO_stepper(target,steps,"FORWARD") + out , isdone=GO_stepper(target,steps,"FORWARD",priority) else: steps=abs(steps) - out , isdone=GO_stepper(target,steps,"BACKWARD") + out , isdone=GO_stepper(target,steps,"BACKWARD",priority) return out , isdone @@ -511,7 +533,7 @@ def get_stepper_HWstatus(target): while (not(isok))and(i<2): i=i+1 recdata=[] - ack= HWcontrol.sendcommand("stepperstatus",sendstring,recdata) + ack= sendcommand("stepperstatus",sendstring,recdata,target,0) print "returned data " , recdata if ack: print target, "correctly activated" @@ -523,7 +545,7 @@ def get_stepper_HWstatus(target): -def GO_stepper(target,steps,direction): +def GO_stepper(target,steps,direction,priority=0): #search the data in IOdata isok=False print "Move Stepper - ", target #only supported the I2C default address, the module supports 2 stepper interfaces: 1,2 @@ -570,7 +592,7 @@ def GO_stepper(target,steps,direction): while (not(isok))and(i<2): i=i+1 recdata=[] - ack= HWcontrol.sendcommand("stepper",sendstring,recdata) + ack= sendcommand("stepper",sendstring,recdata,target,priority) print "returned data " , recdata if ack and recdata[1]!="e": print target, "correctly activated" @@ -590,7 +612,7 @@ def setstepperposition(element, position): return write_status_data(Stepper_Status,element,'position',position) -def getpinstate(target): +def getpinstate(target, priority=0): #search the data in IOdata print "Check PIN state ", target PIN=searchdata(HW_INFO_NAME,target,HW_CTRL_PIN) @@ -602,7 +624,7 @@ def getpinstate(target): while (not(isok))and(i<2): i=i+1 recdata=[] - ack= HWcontrol.sendcommand("readpin",sendstring,recdata) + ack= sendcommand("pinstate",sendstring,recdata,target,priority) print "returned data " , recdata if ack and recdata[1]!="e": value=recdata[1] @@ -626,6 +648,30 @@ def getpinstate(target): return activated +def readinputpin(PIN): + #search the data in IOdata + + print "Read input PIN ", PIN + sendstring=str(PIN) + + isok=False + value=0 + i=0 + while (not(isok))and(i<2): + i=i+1 + recdata=[] + ack= sendcommand("readinputpin",sendstring,recdata,target="") + print "returned data " , recdata + if ack and recdata[2]: + value=recdata[1] + isok=True + else: + value="error" + + return value # either "0" or "1" + + + def getsensornamebymeasure(measure): # MEASURELIST is the list with valid values for the "measure" parameter @@ -687,7 +733,6 @@ def initallGPIOoutput(): - def restoredefault(): filestoragemod.deletefile(HWDATAFILENAME) filestoragemod.readfiledata(DEFHWDATAFILENAME,IOdata) @@ -719,12 +764,16 @@ def changeIOdatatemp(IOname,IOparameter,IOvalue): #needed def searchdata(recordkey,recordvalue,keytosearch): for ln in IOdata: - if recordkey in ln: + if recordkey in ln: if ln[recordkey]==recordvalue: if keytosearch in ln: return ln[keytosearch] return "" + +def deepcopydict(dictin): + return copy.deepcopy(dictin) + def searchrowtemp(recordkey,recordvalue): for ln in IOdatatemp: if recordkey in ln: @@ -953,6 +1002,7 @@ def thumbconsistency(apprunningpath): def shotit(video,istest,resolution,positionvalue,vdirection): + shottaken=False # send command to the actuator for test if istest: filepath=os.path.join(get_path(), "static") @@ -969,14 +1019,17 @@ def shotit(video,istest,resolution,positionvalue,vdirection): else: ret_data = {"answer": "Camera not detected"} print "The photo ", ret_data - return ret_data + return shottaken , ret_data def takephoto(): + isok=False + count=0 print "take photo", " " , datetime.now() videolist=videodevlist() for video in videolist: + isok=False if cameradbmod.isCameraActive(video): resolution=cameradbmod.searchdata("camname",video,"resolution") # if not found return "" position=cameradbmod.searchdata("camname",video,"position") @@ -989,14 +1042,20 @@ def takephoto(): for positionvalue in positionlist: # move servo servoangle(servo,positionvalue,2) - ret_data={} - ret_data=shotit(video,False,resolution,positionvalue,vdirection) + isok , ret_data=shotit(video,False,resolution,positionvalue,vdirection) + else: - ret_data={} - ret_data=shotit(video,False,resolution,"0",vdirection) + isok , ret_data=shotit(video,False,resolution,"0",vdirection) + logger.info(ret_data["answer"]) else: - logger.info("Camera: %s not activated " , video) + logger.info("Camera: %s not activated " , video) + + if isok: + count = count +1 + if count > 0: + isok=True + return isok @@ -1077,22 +1136,22 @@ def get_image_size(picturepath): return width, height def additionalRowInit(): + #initialize IOdatarow + global IOdatarow fields=HWdataKEYWORDS tablehead=[] for key, value in fields.iteritems(): tablehead.append(key) - additionalrow={} + IOdatarow={} for th in tablehead: if len(fields[th])>1: - additionalrow[th]=fields[th][0] + IOdatarow[th]=fields[th][0] else: - additionalrow[th]="" - #initialize IOdatarow - global IOdatarow - IOdatarow=additionalrow + IOdatarow[th]="" return True -def addrow(dicttemp, temp=True): +def addrow(dictrow, temp=True): + dicttemp=copy.deepcopy(dictrow) global IOdata global IOdatatemp if temp: diff --git a/interruptdbmod.py b/interruptdbmod.py new file mode 100644 index 0000000..573aa7f --- /dev/null +++ b/interruptdbmod.py @@ -0,0 +1,303 @@ +# -*- coding: utf-8 -*- +""" +Auto watering UI setting storage utilities +""" + +import logging +import os +import os.path +import sys +import string +from datetime import datetime,date,timedelta +import time +import filestoragemod +import hardwaremod + + + +# ///////////////// -- GLOBAL VARIABLES AND INIZIALIZATION --- ////////////////////////////////////////// + + +global WTDATAFILENAME +WTDATAFILENAME="interruptdata.txt" +global DEFWTDATAFILENAME +DEFWTDATAFILENAME="default/definterruptdata.txt" + +global WTdata +WTdata=[] + +# read WTdata ----- +if not filestoragemod.readfiledata(WTDATAFILENAME,WTdata): #read watering setting file + #read from default file + filestoragemod.readfiledata(DEFWTDATAFILENAME,WTdata) + print "Watering writing default calibration data" + filestoragemod.savefiledata(WTDATAFILENAME,WTdata) + +# end read IOdata ----- + + + +# ///////////////// --- END GLOBAL VARIABLES ------ + + + +#-- start filestorage utility--------//////////////////////////////////////////////////////////////////////////////////// + +# filestoragemod.readfiledata(filename,filedata) +# filestoragemod.savefiledata(filename,filedata) +# filestoragemod.appendfiledata(filename,filedata) +# filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue) +# filestoragemod.deletefile(filename) + +def readfromfile(): + global WTdata + filestoragemod.readfiledata(WTDATAFILENAME,WTdata) + + +def consistencycheck(): + + # this routine align the watering table elements with the Hardware available elements "name" labelled with usedfor "watering" + + elementlist=getelementlist() + recordkey="element" + elementlistfile=[] + for ln in WTdata: + if recordkey in ln: + elementlistfile.append(ln[recordkey]) + + tabletoadd=[] + for tablename1 in elementlist: + found=False + for tablename2 in elementlistfile: + if tablename1==tablename2 : + found=True + if not(found) : + tabletoadd.append(tablename1) + + tabletoremove=[] + for tablename1 in elementlistfile: + found=False + for tablename2 in elementlist: + if tablename1==tablename2 : + found=True + if not(found) : + tabletoremove.append(tablename1) + + #print " ---------------------------------------------------------------------<----------------<-----------______________" + #print "to add ", tabletoadd + #print "to remove " , tabletoremove + #print "WTdata ", WTdata + + # get the dictionary line with an element as reference (from default file) + defWTdata=[] + filestoragemod.readfiledata(DEFWTDATAFILENAME,defWTdata) + for ln in defWTdata: + if recordkey in ln: + referenceln=dict(ln) + break + # copy the previous taken line and change the element parameter + for tablename in tabletoadd: + # add copying from element:"1" + #print "adding table ", tablename + ln=dict(referenceln) + ln[recordkey]=tablename + WTdata.append(ln) + + # remove the dictionalry line that are not consistent with element list + for tablename in tabletoremove: + for ln in WTdata: + if recordkey in ln: + if ln[recordkey]==tablename: + WTdata.remove(ln) + + saveWTsetting() + + # extra code for the sensor field which should be consistent with sensor names in HW + + + +def replacewordandsave(oldword,newword): + global WTdata + filestoragemod.replacewordandsave(WTDATAFILENAME,oldword,newword) + filestoragemod.readfiledata(WTDATAFILENAME,WTdata) + + + +def restoredefault(): + global WTdata + filestoragemod.deletefile(WTDATAFILENAME) + filestoragemod.readfiledata(DEFWTDATAFILENAME,WTdata) + #print "WT data -----------------------------------> ", WTdata + consistencycheck() + + +def saveWTsetting(): + filestoragemod.savefiledata(WTDATAFILENAME,WTdata) + + +def getelementlist(): + recordkey=hardwaremod.HW_INFO_IOTYPE + recordvalue="output" + keytosearch=hardwaremod.HW_INFO_NAME + datalist=hardwaremod.searchdatalist(recordkey,recordvalue,keytosearch) + excludewatercontrol=True + if not excludewatercontrol: + recordkey=hardwaremod.HW_FUNC_USEDFOR + recordvalue="watercontrol" + keytosearch=hardwaremod.HW_INFO_NAME + removelist=hardwaremod.searchdatalist(recordkey,recordvalue,keytosearch) + for element in removelist: + datalist.remove(element) + + print "elementlist= ",datalist + return datalist + +def sensorlist(): + tablelist=hardwaremod.searchdatalist2keys(hardwaremod.HW_INFO_IOTYPE,"input", hardwaremod.HW_CTRL_CMD, "interrupt" ,hardwaremod.HW_INFO_NAME) + return tablelist + +def sensorlisttriggertime(): + tablelist=hardwaremod.searchdatalist(hardwaremod.HW_INFO_IOTYPE,"input",hardwaremod.HW_INFO_NAME) + timetriggerlist=[] + for item in tablelist: + timelist=hardwaremod.gettimedata(item) + theinterval=timelist[1] # minutes + timetriggerlist.append(theinterval) + return timetriggerlist + + +def gethygrosensorfromactuator(actuatorname): + recordkey="element" + recordvalue=actuatorname + keytosearch="sensor" + if searchdata(recordkey,recordvalue,"workmode")!="None": + return searchdata(recordkey,recordvalue,keytosearch) + else: + return "" + + + + +def getrowdata(recordvalue,paramlist,index): #for parameters with array of integers + recordkey="element" + datalist=[] + for ln in WTdata: + if recordkey in ln: + if ln[recordkey]==recordvalue: + for param in paramlist: + try: + datalist.append(int(ln[param][index])) + except Exception, e: + print 'Failed to load value, set value to zero. Error: '+ str(e) + datalist.append(0) + + return datalist + +def gettable(index): + paramlist=getparamlist() + #print "paramlist" , paramlist + elementlist=getelementlist() + datalist=[] + for row in elementlist: + rowdatalist=getrowdata(row,paramlist,index) + datalist.append(rowdatalist) + #print datalist + return datalist + + +def replacerow(element,dicttemp): + searchfield="element" + searchvalue=element + for line in WTdata: + if searchfield in line: + if line[searchfield]==searchvalue: + for row in line: + line[row]=dicttemp[row] + filestoragemod.savefiledata(WTDATAFILENAME,WTdata) + return True + return False + + + +def changesaveWTsetting(WTname,WTparameter,WTvalue): +# questo il possibile dizionario: { 'name':'', 'm':0.0, 'q':0.0, 'lastupdate':'' } #variabile tipo dizionario + for line in WTdata: + if line["name"]==WTname: + line[WTparameter]=WTvalue + saveWTsetting() + return True + return False + +def searchdata(recordkey,recordvalue,keytosearch): + for ln in WTdata: + if recordkey in ln: + if ln[recordkey]==recordvalue: + if keytosearch in ln: + return ln[keytosearch] + return "" + +def gettimedata(name): + # return list with three integer values: hour , minute, second + timestr=searchdata("name",name,"time") + returntime=[] + if not timestr=="": + timelist=timestr.split(":") + for timeitem in timelist: + returntime.append(timeitem) + if len(timelist)<3: + returntime.append("00") + return returntime + else: + return ["00","00","00"] + + + +def searchdatalist(recordkey,recordvalue,keytosearch): + datalist=[] + for ln in WTdata: + if recordkey in ln: + if ln[recordkey]==recordvalue: + if keytosearch in ln: + datalist.append(ln[keytosearch]) + return datalist + +def getfieldvaluelist(fielditem,valuelist): + del valuelist[:] + for line in WTdata: + valuelist.append(line[fielditem]) + +def getfieldinstringvalue(fielditem,stringtofind,valuelist): + del valuelist[:] + for line in WTdata: + name=line[fielditem] + if name.find(stringtofind)>-1: + valuelist.append(name) + + + + +def get_path(): + '''Get the path to this script no matter how it's run.''' + #Determine if the application is a py/pyw or a frozen exe. + if hasattr(sys, 'frozen'): + # If run from exe + dir_path = os.path.dirname(sys.executable) + elif '__file__' in locals(): + # If run from py + dir_path = os.path.dirname(__file__) + else: + # If run from command line + dir_path = sys.path[0] + return dir_path + +#--end --------//////////////////////////////////////////////////////////////////////////////////// + + +if __name__ == '__main__': + # comment + a=10 + + + + + diff --git a/interruptmod.py b/interruptmod.py new file mode 100644 index 0000000..86edae4 --- /dev/null +++ b/interruptmod.py @@ -0,0 +1,372 @@ +import logging +from datetime import datetime , time ,timedelta +import hardwaremod +import os +import subprocess +import emailmod +import interruptdbmod +import sensordbmod +import actuatordbmod +import autofertilizermod +import statusdataDBmod +import threading +import time as t + +global ISRPI + +try: + __import__("smbus") +except ImportError: + ISRPI=False +else: + import RPi.GPIO as GPIO + GPIO.setmode(GPIO.BCM) + ISRPI=True + + +ACTIONPRIORITYLEVEL=5 +NONBLOCKINGPRIORITY=0 + +#In hardware, a 10K resistor between the input channel and 3.3V (pull-up) or 0V (pull-down) is commonly used. +#https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/ + +logger = logging.getLogger("hydrosys4."+__name__) + +# status array, required to check the ongoing actions +elementlist= interruptdbmod.getelementlist() +waitingtime=1200 +AUTO_data={} # dictionary of dictionary +AUTO_data["default"]={"lasteventtime":datetime.utcnow()- timedelta(minutes=waitingtime),"lastactiontime":datetime.utcnow()- timedelta(minutes=waitingtime),"actionvalue":0, "alertcounter":0, "infocounter":0, "status":"ok" , "threadID":None , "blockingstate":False} + + +def readstatus(element,item): + return statusdataDBmod.read_status_data(AUTO_data,element,item) + + +def eventcallback(PIN): + t.sleep(0.05) + reading=hardwaremod.readinputpin(PIN) + if reading=="1": + print "************************* Rising edge detected on PIN:", PIN + recordkey=hardwaremod.HW_CTRL_PIN + recordvalue=str(PIN) + keytosearch=hardwaremod.HW_INFO_NAME + refsensor=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) + print "reference sensor:" , refsensor + if refsensor!="": + interruptcheck(refsensor) + else: + print "Falling edge detected on PIN" , PIN + + + + +def setinterruptevents(): + + if ISRPI: + alloutputpinlist=["2", "3", "4","5","6", "7", "8", "9", "10", "11", "12","13","14", "15", "16","17", "18", "19", "20","21","22", "23", "24", "25","26", "27"] + for channel in alloutputpinlist: + GPIO.remove_event_detect(hardwaremod.toint(channel,2)) + + + interruptlist=hardwaremod.searchdatalist2keys(hardwaremod.HW_INFO_IOTYPE,"input", hardwaremod.HW_CTRL_CMD, "interrupt" ,hardwaremod.HW_INFO_NAME) + for item in interruptlist: + # get PIN number + recordkey=hardwaremod.HW_INFO_NAME + recordvalue=item + keytosearch=hardwaremod.HW_CTRL_PIN + PINstr=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) + PIN=hardwaremod.toint(PINstr,-1) + if PIN>-1: + + keytosearch=hardwaremod.HW_CTRL_LOGIC + logic=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) + # set Sw pull up / down mode + + if logic=="pos": + GPIO.setup(PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) + evenslopetype=GPIO.BOTH + else: + GPIO.setup(PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) + evenslopetype=GPIO.BOTH + + #GPIO.RISING, GPIO.FALLING or GPIO.BOTH. + # ignoring further edges for 200ms for switch bounce handling + # link to the callback function + GPIO.add_event_detect(PIN, evenslopetype, callback=eventcallback, bouncetime=200) + + + return "" + + + + + + + +def cyclereset(element): + global AUTO_data + waitingtime=hardwaremod.toint(interruptdbmod.searchdata("element",element,"preemptive_period"),0) + AUTO_data[element]={"lastactiontime":datetime.utcnow() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} + AUTO_data[element]={"lasteventtime":datetime.utcnow() - timedelta(minutes=waitingtime),"status":"ok","actionvalue":0, "alertcounter":0, "infocounter":0} + + + +def cycleresetall(): + global AUTO_data + elementlist= interruptdbmod.getelementlist() + for element in elementlist: + cyclereset(element) + + + +def interruptcheck(refsensor): + logger.info('Starting Interrupt Evaluation, Sensor: %s' , refsensor) + # iterate among the actuators + elementlist= interruptdbmod.getelementlist() + for element in elementlist: + sensor=interruptdbmod.searchdata("element",element,"sensor") + if sensor==refsensor: + interruptexecute(refsensor,element) + return + + +def interruptexecute(refsensor,element): + sensor=refsensor + logger.info('interrupt Pairing OK ---> Actuator: %s , Sensor: %s', element, sensor) + # check the mode + modelist=["None", "Pre-emptive Blocking"] + workmode=checkworkmode(element) + + if (workmode=="None"): + # None case + print "No Action required, workmode set to None, element: " , element + logger.info("No Action required, workmode set to None, element: %s " , element) + return + + if (workmode==""): + logger.info("Not able to get the workmode: %s " , element) + return + + logger.info('Interrupt, Get all the parameters') + actuatoroutput=hardwaremod.tonumber(interruptdbmod.searchdata("element",element,"actuator_output"),0) + actuatoroutputfollowup=hardwaremod.tonumber(interruptdbmod.searchdata("element",element,"folloup_output"),0) + + # evaluate variables for operational period check + starttime = datetime.strptime(interruptdbmod.searchdata("element",element,"allowedperiod")[0], '%H:%M').time() + endtime = datetime.strptime(interruptdbmod.searchdata("element",element,"allowedperiod")[1], '%H:%M').time() + + + # get other parameters + seonsormode=interruptdbmod.searchdata("element",element,"sensor_mode") + + preemptiontime=hardwaremod.toint(interruptdbmod.searchdata("element",element,"preemptive_period"),1) + + mailtype=interruptdbmod.searchdata("element",element,"mailalerttype") + + actionmodeafterfirst=interruptdbmod.searchdata("element",element,"actionmode_afterfirst") + + + # ------------------------ interrupt alghoritm + + if workmode=="Pre-emptive Blocking": + # check if inside the allowed time period + print "Pre-emptive Blocking Mode" + logger.info('Pre-emptive Blocking mode --> %s', element) + timeok=isNowInTimePeriod(starttime, endtime, datetime.now().time()) # don't use UTC here! + print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime + if timeok: + logger.info('inside allowed time') + + CheckActivateNotify(element,sensor,preemptiontime,actuatoroutput,actionmodeafterfirst,actuatoroutputfollowup,mailtype) + + else: + logger.info('out of allowed operational time') + + # implment Critical alert message in case the sensor value is one interval more than Max_threshold + + return + + +def CheckActivateNotify(element,sensor,preemptiontime,actuatoroutput,actionmodeafterfirst,actuatoroutputfollowup,mailtype): + value=actuatoroutput + isok=False + global AUTO_data + # check if in blocking state + lasteventtime=statusdataDBmod.read_status_data(AUTO_data,element,"lasteventtime") + blockingstate=statusdataDBmod.read_status_data(AUTO_data,element,"blockingstate") + print ' Previous event: ' , lasteventtime , ' Now: ', datetime.utcnow() + #timedifference=sensordbmod.timediffinminutes(lasteventtime,datetime.utcnow()) + #print 'Time interval between actions', timedifference ,'. threshold', preemptiontime + #logger.info('Time interval between Actions %d threshold %d', timedifference,preemptiontime) + if not blockingstate: # outside the preemption period , first activation + print " outside the preemption period " + logger.info('outside the preemption period') + # action + print "Implement Actuator Value ", value + logger.info('Procedure to start actuator %s, for value = %s', element, value) + isok=activateactuator(element, value) + + # invia mail, considered as info, not as alert + if mailtype!="warningonly": + textmessage="INFO: " + sensor + " event , activating:" + element + " with Value " + str(value) + emailmod.sendallmail("alert", textmessage) + if isok: + statusdataDBmod.write_status_data(AUTO_data,element,"lasteventtime",datetime.utcnow()) + statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) + statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) + startblockingstate(element,preemptiontime) + + else: + # inside blocking state + print " inside the preemption period, starting followup actions: " , actionmodeafterfirst + logger.info('inside the preemption period, check followup actions %s :', actionmodeafterfirst) + + if actionmodeafterfirst=="None": + return + + if actionmodeafterfirst=="Extend blocking state" or actionmodeafterfirst=="Extend and Follow-up": # extend only the pre-emption blocking period, no action + print "Extend blocking state" + startblockingstate(element,preemptiontime) + + if actionmodeafterfirst=="Remove blocking state" or actionmodeafterfirst=="Remove and Follow-up": # remove the pre-emption blocking period, no action + print "Remove blocking state" + endblocking(element,preemptiontime) + + + if actionmodeafterfirst=="Follow-up action" or actionmodeafterfirst=="Extend and Follow-up" or actionmodeafterfirst=="Remove and Follow-up": # execute the action followup, no variation in the preemption period + value=actuatoroutputfollowup + # followup action + print "Implement Actuator Value followup", value + logger.info('Procedure to start actuator followup %s, for value = %s', element, value) + isok=activateactuator(element, value) + + # invia mail, considered as info, not as alert + if mailtype!="warningonly": + textmessage="INFO: " + sensor + " event , activating:" + element + " with Value " + str(value) + emailmod.sendallmail("alert", textmessage) + if isok: + statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) + statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) + + return isok + + +def startblockingstate(element,period): + if period>0: + global AUTO_data + # in case another timer is active on this element, cancel it + threadID=statusdataDBmod.read_status_data(AUTO_data,element,"threadID") + if threadID!=None and threadID!="": + print "cancel the Thread of element=",element + threadID.cancel() + + statusdataDBmod.write_status_data(AUTO_data,element,"blockingstate",True) + statusdataDBmod.write_status_data(hardwaremod.Blocking_Status,element,"priority",ACTIONPRIORITYLEVEL) #increse the priority to execute a command + + periodsecond=period*60 + nonblockingpriority=0 + threadID = threading.Timer(periodsecond, endblocking, [element , period]) + threadID.start() + statusdataDBmod.write_status_data(AUTO_data,element,"threadID",threadID) + + + + +def endblocking(element, period): + if checkstopcondition(element): + global AUTO_data + print "Start removing blocking status" + statusdataDBmod.write_status_data(hardwaremod.Blocking_Status,element,"priority",NONBLOCKINGPRIORITY) #put the priority to lower levels + statusdataDBmod.write_status_data(AUTO_data,element,"threadID",None) + statusdataDBmod.write_status_data(AUTO_data,element,"blockingstate",False) + else: + print "Interrupt LEVEL High, Do not stop blocking period, Extend it" + startblockingstate(element,period) + + +def checkstopcondition(element): + print "Evaluating End of Blocking period ++++++++++++" + actionmodeafterfirst=interruptdbmod.searchdata("element",element,"actionmode_afterfirst") + print actionmodeafterfirst + if actionmodeafterfirst=="Extend blocking state" or actionmodeafterfirst=="Extend and Follo-up": # extend only the pre-emption blocking period, no action + seonsormode=interruptdbmod.searchdata("element",element,"sensor_mode") + print seonsormode + if seonsormode=="Edge + Level": + sensor=interruptdbmod.searchdata("element",element,"sensor") + recordkey=hardwaremod.HW_INFO_NAME + recordvalue=sensor + keytosearch=hardwaremod.HW_CTRL_PIN + PIN=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) + reading=hardwaremod.readinputpin(PIN) + keytosearch=hardwaremod.HW_CTRL_LOGIC + logic=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) + # pin high according to the set logic + print "logic:", logic , " reading:" ,reading + if logic=="pos" and reading=="1": + return False + if logic=="neg" and reading=="0": + return False + + return True + + + + + +def activateactuator(target, value): # return true in case the state change: activation is >0 or a different position from prevoius position. + # check the actuator + isok=False + actuatortype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,target,hardwaremod.HW_CTRL_CMD) + supportedactuators=["pulse","servo","stepper"] + # stepper motor + if actuatortype=="stepper": + out, isok = hardwaremod.GO_stepper_position(target,value,priority=ACTIONPRIORITYLEVEL) + if isok: + actuatordbmod.insertdataintable(target,value) + + # pulse + if actuatortype=="pulse": + duration=hardwaremod.toint(value,0) + # check the fertilizer doser flag before activating the pulse + doseron=autofertilizermod.checkactivate(target,duration) + # start pulse + pulseok=hardwaremod.makepulse(target,duration,priority=ACTIONPRIORITYLEVEL) + # salva su database + if "Started" in pulseok: + actuatordbmod.insertdataintable(target,duration) + isok=True + + # servo motor + if actuatortype=="servo": + out, isok = hardwaremod.servoangle(target,value,0.5,priority=ACTIONPRIORITYLEVEL) + if isok: + actuatordbmod.insertdataintable(target,value) + + return isok + + +def isNowInTimePeriod(startTime, endTime, nowTime): + print startTime," ", endTime," " , nowTime + if startTime < endTime: + return nowTime >= startTime and nowTime <= endTime + else: #Over midnight + return nowTime >= startTime or nowTime <= endTime + + + +def checkworkmode(element): + return interruptdbmod.searchdata("element",element,"workmode") + + + + + +if __name__ == '__main__': + + """ + prova functions + """ + + + diff --git a/networkmod.py b/networkmod.py index be2a549..ee22c25 100644 --- a/networkmod.py +++ b/networkmod.py @@ -139,6 +139,30 @@ def iwcommand(cmd,wordtofind): ssids.append(ssid) return ssids +def gethostname(): + print "Get hostname" + cmd = ['hostname'] + try: + output_string = subprocess.check_output(cmd).decode('utf-8').strip() + time.sleep(0.5) + print output_string + return output_string + except subprocess.CalledProcessError as e: + print "error to execute the command" , cmd + logger.error("error to execute the command %s",cmd) + return "error" + +def setnewhostname(HOSTNAME): + print "Set hostname" + # hostnamectl set-hostname $NewHostName + cmd = [ "hostnamectl" , 'set-hostname' , HOSTNAME] + try: + output_string = subprocess.check_output(cmd).decode('utf-8').strip() + return output_string + except subprocess.CalledProcessError as e: + print "error to execute the command" , cmd + logger.error("error to execute the command %s",cmd) + return "error" def start_hostapd(): @@ -783,6 +807,26 @@ def get_local_ip(): print ipaddr return ipaddr + +def get_local_ip_list(): + cmd = ["hostname -I"] + try: + cmd_output = subprocess.check_output(cmd, shell=True).decode('utf-8') + except: + print "error to execute the command" , cmd + logger.error("error to execute the command %s",cmd) + print "Local IP Error " + logger.error('Error to get local IP') + return "" + ipaddrlist=[] + stringlist=cmd_output.split(" ") + for ipstrings in stringlist: + isaddress , ipaddr = IPv4fromString(ipstrings) + if isaddress: + ipaddrlist.append(ipaddr) + print ipaddr + return ipaddrlist + def get_local_ip_raw(): cmd = ["hostname -I"] try: diff --git a/selectedplanmod.py b/selectedplanmod.py index 8a624bb..939b0e3 100644 --- a/selectedplanmod.py +++ b/selectedplanmod.py @@ -64,9 +64,8 @@ def pulsenutrient(target,activationseconds): #scheduled doser activity for ferti if autofertilizermod.isschedulermode(target): autofertilizermod.activatedoser(target, duration) else: - autofertilizermod.AUTO_data[target]["tobeactivated"]=True - autofertilizermod.AUTO_data[target]["duration"]=duration - autofertilizermod.AUTO_data[target]["triggerdate"]=datetime.now() + logger.info('Book the %s activation', target) + autofertilizermod.setActivationDurationDate(target,True,duration,datetime.now()) return True @@ -119,7 +118,9 @@ def startpump(target,activationseconds,MinAveragetemp,MaxAverageHumid): hsensorname=hsensornamelist[0] # get first found sensor in the list sensordbmod.getsensordbdata(hsensorname,sensordata) starttimecalc=datetime.now()-timedelta(minutes=int(MinutesOfAverage)) - humquantity=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now())["average"] + isok , quantitylist=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now()) + humquantity=quantitylist["average"] + logger.info('Waterpump Check parameter if humquantity=%s < MaxAverageHumid=%s ', str(humquantity), str(MaxAverageHumid)) print 'Waterpump Check parameter if humquantity=',humquantity,' < MaxAverageHumid=' ,MaxAverageHumid @@ -138,7 +139,8 @@ def startpump(target,activationseconds,MinAveragetemp,MaxAverageHumid): tsensorname=tsensornamelist[0] # get first found sensor in the list sensordbmod.getsensordbdata(tsensorname,sensordata) starttimecalc=datetime.now()-timedelta(minutes=int(MinutesOfAverage)) - tempquantity=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now())["average"] + isok , quantitylist=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now()) + tempquantity=quantitylist["average"] logger.info('Waterpump Check parameter if tempquantity=%s > MinAveragetemp=%s ', str(tempquantity), str(MinAveragetemp)) print 'Waterpump Check parameter if tempquantity=',tempquantity,' > MinAveragetemp=' ,MinAveragetemp @@ -271,6 +273,7 @@ def heartbeat(): # check if there have been errors in Syslog if DEBUGMODE: + logger.info('Heartbeat check , check errors in Syslog file') Errortextlist=debuggingmod.searchsyslogkeyword("error") if Errortextlist: print "found error in syslog" @@ -285,6 +288,7 @@ def heartbeat(): # check if there have been errors in Schedulerlog if DEBUGMODE: + logger.info('Heartbeat check , check errors in Sched log file') filename="logfiles/apscheduler_hydrosystem.log" MYPATH=hardwaremod.get_path() filenameandpath=os.path.join(MYPATH, filename) @@ -316,9 +320,10 @@ def sendmail(target): def takephoto(target): logger.info('take picture %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) - hardwaremod.takephoto() + isok=hardwaremod.takephoto() # save action in database - actuatordbmod.insertdataintable(target,1) + if isok: + actuatordbmod.insertdataintable(target,1) print "Action", target ," " , datetime.now() return True diff --git a/sensordbmod.py b/sensordbmod.py index a4a8bfa..589aca0 100644 --- a/sensordbmod.py +++ b/sensordbmod.py @@ -115,9 +115,15 @@ def getsensordbdatadays(selsensor,sensordata,days): fieldlist.append(TIMEFIELD) fieldlist.append(DATAFIELD) sampletime=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,selsensor,hardwaremod.HW_FUNC_TIME) - samplingintervalminutes=int(sampletime.split(":")[1]) - samplesnumber=(days*24*60)/samplingintervalminutes - databasemod.getdatafromfieldslimit(DBFILENAME,selsensor,fieldlist,sensordata,samplesnumber) + if sampletime!="": + samplingintervalminutes=int(sampletime.split(":")[1]) + if samplingintervalminutes>=1: + samplesnumber=(days*24*60)/samplingintervalminutes + databasemod.getdatafromfieldslimit(DBFILENAME,selsensor,fieldlist,sensordata,samplesnumber) + else: + databasemod.getdatafromfields(DBFILENAME,selsensor,fieldlist,sensordata) + else: + databasemod.getdatafromfields(DBFILENAME,selsensor,fieldlist,sensordata) def getsensordbdatasamplesN(selsensor,sensordata,samplesnumber): fieldlist=[] @@ -197,6 +203,7 @@ def getAllSensorsDataPeriodv2(enddate,pastdays): num = int(pastdays) tdelta=timedelta(days=num) startdate=enddate-tdelta + print "sensordbmod " print " stratdate " ,startdate print " enddate ", enddate outputallsensordata=[] @@ -206,7 +213,9 @@ def getAllSensorsDataPeriodv2(enddate,pastdays): for selsensor in sensorlist: allsensordata=[] #getsensordbdata(selsensor,allsensordata) - getsensordbdatadays(selsensor,allsensordata,num) + #print " reading sensor database " , selsensor + getsensordbdatadays(selsensor,allsensordata,num+(datetime.now()-enddate).days+1) + #print " reading sensor database DONE!" sensordata=[] # fetch raw data from database for rowdata in allsensordata: @@ -221,11 +230,13 @@ def getAllSensorsDataPeriodv2(enddate,pastdays): mintime=dateinsecepoch if maxtime0: outputallsensordata.append(sensordata) usedsensorlist.append(selsensor) + + print return outputallsensordata,usedsensorlist,mintime,maxtime # sensor data -------------------------------------------- @@ -254,6 +265,7 @@ def RemoveSensorDataPeriod(removebeforedays): def EvaluateDataPeriod(sensordata,startdate,enddate): # sensor data -------------------------------------------- + isok=False outputdata={} summa=0 inde=0 @@ -278,6 +290,7 @@ def EvaluateDataPeriod(sensordata,startdate,enddate): if inde>0: average=summa/inde + isok=True else: average=0 mini=0 @@ -287,7 +300,7 @@ def EvaluateDataPeriod(sensordata,startdate,enddate): outputdata["average"]=average outputdata["min"]=mini outputdata["max"]=maxi - return outputdata + return isok , outputdata def SumProductDataPeriod(sensordata,startdate,enddate,timeinterval): # sensor data -------------------------------------------- @@ -342,7 +355,7 @@ def sensorsysinfomatrix(): #set date interval for average endtime=datetime.now() starttime= endtime - timedelta(days=1) - evaluateddata=EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=EvaluateDataPeriod(sensordata,starttime,endtime) row.append(str('%.1f' % evaluateddata["average"])) row.append(str('%.1f' % evaluateddata["min"])) row.append(str('%.1f' % evaluateddata["max"])) diff --git a/start.py b/start.py index e8df58a..64681e5 100644 --- a/start.py +++ b/start.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -Release="1.00" +Release="1.05a" #--------------------- from loggerconfig import LOG_SETTINGS @@ -49,6 +49,10 @@ import automationdbmod import automationmod +import interruptdbmod +import interruptmod + + import autofertilizerdbmod import autofertilizermod import fertilizerdbmod @@ -64,6 +68,9 @@ import cameradbmod import sysconfigfilemod import debuggingmod +import filemanagementmod + + # Raspberry Pi camera module (requires picamera package) from camera_pi import Camera @@ -103,13 +110,21 @@ def runallconsistencycheck(): wateringdbmod.consitencycheck() autowateringdbmod.consistencycheck() automationdbmod.consistencycheck() + interruptdbmod.consistencycheck() fertilizerdbmod.consitencycheck() autofertilizerdbmod.consistencycheck() sensordbmod.consistencycheck() actuatordbmod.consistencycheck() return True - +def runallreadfile(): + wateringdbmod.readfromfile() + autowateringdbmod.readfromfile() + automationdbmod.readfromfile() + interruptdbmod.readfromfile() + fertilizerdbmod.readfromfile() + autofertilizerdbmod.readfromfile() + return True # Setup mode of operation------------------------------ @@ -123,6 +138,9 @@ def runallconsistencycheck(): #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() +#initialize interrupt +interruptmod.setinterruptevents() + # GET path --------------------------------------------- print "path ",hardwaremod.get_path() MYPATH=hardwaremod.get_path() @@ -142,6 +160,7 @@ def runallconsistencycheck(): # after internet connection because ofter the time is abruptly changed after connection selectedplanmod.waitandsetmastercallback(networkmod.WAITTOCONNECT, 15) # plus 40 seconds respect to internet connection + #prove varie qui --------------------------------------------------- #selectedplanmod.startpump("1","10","25","10") @@ -222,7 +241,7 @@ def show_entries(): sensordbmod.getsensordbdatadays(name,sensordata,1) #set date interval for average starttime= endtime - timedelta(days=1) - evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % evaluateddata["average"]) @@ -257,7 +276,7 @@ def show_entries(): sensordbmod.getsensordbdatadays(name,sensordata,1) #set date interval for average starttime= endtime - timedelta(days=1) - evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % evaluateddata["average"]) @@ -292,7 +311,7 @@ def show_entries(): sensordbmod.getsensordbdatadays(name,sensordata,1) #set date interval for average starttime= endtime - timedelta(days=1) - evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % evaluateddata["average"]) @@ -327,7 +346,7 @@ def show_entries(): sensordbmod.getsensordbdatadays(name,sensordata,1) #set date interval for average starttime= endtime - timedelta(days=1) - evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % evaluateddata["average"]) @@ -362,7 +381,7 @@ def show_entries(): sensordbmod.getsensordbdatadays(name,sensordata,1) #set date interval for average starttime= endtime - timedelta(days=1) - evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(sensordata,starttime,endtime) paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % evaluateddata["average"]) @@ -400,7 +419,7 @@ def show_entries(): starttime= endtime - timedelta(days=1) data=[] actuatordbmod.getActuatordbdata(name,data) - evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % (evaluateddata["sum"])) @@ -435,7 +454,7 @@ def show_entries(): starttime= endtime - timedelta(days=1) data=[] actuatordbmod.getActuatordbdata(name,data) - evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % (evaluateddata["sum"])) @@ -470,7 +489,7 @@ def show_entries(): starttime= endtime - timedelta(days=1) data=[] actuatordbmod.getActuatordbdata(name,data) - evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % (evaluateddata["sum"])) @@ -509,7 +528,7 @@ def show_entries(): starttime= endtime - timedelta(days=1) data=[] actuatordbmod.getActuatordbdata(name,data) - evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average + isok, evaluateddata=sensordbmod.EvaluateDataPeriod(data,starttime,endtime) #set date interval for average paneldatarow={} paneldatarow["name"]=name paneldatarow["average"]=str('%.1f' % (evaluateddata["sum"])) @@ -550,8 +569,11 @@ def network(): iplocal=networkmod.get_local_ip() + iplocallist=networkmod.get_local_ip_list() + ipext=networkmod.get_external_ip() iplocalwifi=networkmod.IPADDRESS ipport=networkmod.PUBLICPORT + hostname=networkmod.gethostname() connectedssidlist=networkmod.connectedssid() if len(connectedssidlist)>0: connectedssid=connectedssidlist[0] @@ -563,7 +585,7 @@ def network(): print " localwifisystem = ", localwifisystem , " connectedssid ", connectedssid - return render_template('network.html',filenamelist=filenamelist, connectedssid=connectedssid,localwifisystem=localwifisystem, iplocal=iplocal, iplocalwifi=iplocalwifi , ipport=ipport) + return render_template('network.html',filenamelist=filenamelist, connectedssid=connectedssid,localwifisystem=localwifisystem, ipext=ipext, iplocallist=iplocallist , iplocal=iplocal, iplocalwifi=iplocalwifi , ipport=ipport , hostname=hostname) @@ -831,7 +853,7 @@ def doit(): hardwaremod.servoangle(servo,position,1) # take picture #vdirection=hardwaremod.searchdata(hardwaremod.HW_FUNC_USEDFOR,"photocontrol",hardwaremod.HW_CTRL_LOGIC) - ret_data=hardwaremod.shotit(video,True,resolution,position,vdirection) + isok, ret_data=hardwaremod.shotit(video,True,resolution,position,vdirection) elif name=="mail": mailaname=request.args['element'] @@ -939,10 +961,8 @@ def saveit(): ret_data = {"answer": "saved"} print "The actuator ", ret_data return jsonify(ret_data) - - - - + + @application.route('/downloadit/', methods=['GET']) def downloadit(): @@ -1041,6 +1061,19 @@ def downloadit(): answer="ready" dstfilenamelist=[] dstfilenamelist.append("download/"+dstfilename) + + elif name=="configzip": + dstfilename=filemanagementmod.configfilezip() + if dstfilename=="": + answer="problem cretating file" + else: + answer="ready" + + dstfilenamelist=[] + dstfilenamelist.append(dstfilename) + + + ret_data = {"answer": answer, "filename": dstfilenamelist} print "The actuator ", ret_data @@ -1126,6 +1159,7 @@ def networksetting(): AP_SSID=request.form['AP_SSID'] AP_PASSWORD=request.form['AP_PASSWORD'] AP_TIME=request.form['AP_TIME'] + HOSTNAME=request.form['HOSTNAME'] @@ -1148,12 +1182,14 @@ def networksetting(): IPADDRESSold=networkmod.IPADDRESS AP_SSIDold=networkmod.localwifisystem AP_TIMEold=str(networkmod.WAITTOCONNECT) + HOSTNAMEold=networkmod.gethostname() + print "save in network file in database" networkdbmod.changesavesetting('LocalIPaddress',IPADDRESS) networkdbmod.changesavesetting('LocalAPSSID',AP_SSID) - networkdbmod.changesavesetting('APtime',AP_TIME) + networkdbmod.changesavesetting('APtime',AP_TIME) # save and change values in the HOSTAPD config file @@ -1172,6 +1208,10 @@ def networksetting(): # save changes in DNSMASQ confign file sysconfigfilemod.modifydnsmasqconfigfile(IPADDRESSold, IPADDRESS) + if HOSTNAME!=HOSTNAMEold: + networkmod.setnewhostname(HOSTNAME) + + # proceed with changes networkmod.applyparameterschange(AP_SSID, AP_PASSWORD, IPADDRESS) networkmod.WAITTOCONNECT=AP_TIME @@ -1194,7 +1234,7 @@ def networksetting(): return redirect(url_for('network')) - + HOSTNAME=networkmod.gethostname() iplocal=networkmod.get_local_ip() IPADDRESS=networkmod.IPADDRESS PORT=networkmod.PUBLICPORT @@ -1209,7 +1249,7 @@ def networksetting(): - return render_template('networksetting.html', IPADDRESS=IPADDRESS, AP_SSID=AP_SSID, AP_PASSWORD=AP_PASSWORD, AP_TIME=AP_TIME) + return render_template('networksetting.html', IPADDRESS=IPADDRESS, AP_SSID=AP_SSID, AP_PASSWORD=AP_PASSWORD, AP_TIME=AP_TIME , HOSTNAME=HOSTNAME) @@ -1238,6 +1278,7 @@ def show_Calibration(): #on the contrary of the name, this show the setting men networkmod.restoredefault() logindbmod.restoredefault() cameradbmod.restoredefault() + interruptdbmod.restoredefault() # try to align the config to new setting (this is not tested properly, better reboot in this case) wateringdbmod.consitencycheck() fertilizerdbmod.consitencycheck() @@ -1245,9 +1286,48 @@ def show_Calibration(): #on the contrary of the name, this show the setting men selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() + interruptmod.setinterruptevents() if requesttype=="editnames": return hardwaresettingeditfield() + + if requesttype=="uploadfile": + print "upload" + + + if 'file' not in request.files: + flash('No file') + else: + f = request.files['file'] + if f.filename == '': + flash('No file selected') + else: + if ".zip" in f.filename: + # control if the folder exist otherwise create it + uploadfolder=application.config['UPLOAD_FOLDER'] + fullfolderpath=os.path.join(MYPATH, uploadfolder) + if not os.path.exists(fullfolderpath): + os.makedirs(fullfolderpath) + print " folder has been created" + + f = request.files['file'] + #f.save(f.filename) + f.save(os.path.join(uploadfolder, f.filename)) + filemanagementmod.restoreconfigfilefromzip(fullfolderpath) + + #align the files and memory + runallreadfile() + # align the data + runallconsistencycheck() + #scheduler setup--------------------- + selectedplanmod.resetmastercallback() + #initiate the GPIO OUT pins + hardwaremod.initallGPIOoutput() + interruptmod.setinterruptevents() + + else: + flash('Allowed file types is .zip ') + actuatorlist=[] actuatorlist=hardwaremod.searchdatalist(hardwaremod.HW_CTRL_CMD,"pulse",hardwaremod.HW_INFO_NAME) @@ -1340,7 +1420,8 @@ def show_sensordata(): if not session.get('logged_in'): return render_template('login.html',error=None, change=False) #---------------- - periodlist=["Day","Week","Month","Year"] + DATEFORMAT="%d/%m/%Y" + periodlist=["Day","Week","Month","Year","Custom"] perioddaysdict={"Day":1,"Week":7,"Month":31,"Year":365} periodtype=periodlist[0] @@ -1349,9 +1430,14 @@ def show_sensordata(): if request.method == 'POST': periodtype=request.form['period'] actiontype=request.form['actionbtn'] + startdatestr = request.form['startdate'] + enddatestr = request.form['enddate'] + elif request.method == 'GET': periodtype = request.args.get('period') actiontype = request.args.get('actionbtn') + startdatestr = request.args.get('startdate') + enddatestr = request.args.get('enddate') if periodtype==None: actiontype="show" periodtype=periodlist[0] @@ -1363,6 +1449,8 @@ def show_sensordata(): hygroactuatornumlist=[] hygrosensornumlist=[] hygrosensornumlistwithout=[] + actuatornumlistwithout=[] + hygrosensornumlistwithoutactive=[] if actiontype=="delete": print "delete all records" @@ -1373,41 +1461,88 @@ def show_sensordata(): else: - #if actiontype=="sensor": - sensorlist=sensordbmod.gettablelist() - startdate=datetime.now() - #sensordbmod.getSensorDataPeriod(sensortype,sensordata,startdate,perioddaysdict[periodtype]) - sensordata, usedsensorlist, mintime, maxtime = sensordbmod.getAllSensorsDataPeriodv2(startdate,perioddaysdict[periodtype]) - #if actiontype=="actuator": - actuatorlist=actuatordbmod.gettablelist() - startdate=datetime.now() - #actuatordbmod.getActuatorDataPeriod(sensortype,sensordata,startdate,perioddaysdict[periodtype]) - actuatordata,usedactuatorlist=actuatordbmod.getAllActuatorDataPeriodv2(startdate,perioddaysdict[periodtype]) + sensorlist=sensordbmod.gettablelist() + + + if periodtype!="Custom": + daysinthepast=perioddaysdict[periodtype] + enddate=datetime.now() + startdate = enddate - timedelta(days=daysinthepast) + else: + startdate=datetime.strptime(startdatestr, DATEFORMAT) + enddate=datetime.strptime(enddatestr, DATEFORMAT) + # check days in the future + daysinthefuture=(datetime.now()-enddate).days + if daysinthefuture<0: + enddate=datetime.now() + # check enddate is after the startdate + daysinthepast=(enddate-startdate).days + if daysinthepast<0: + daysinthepast=1 + startdate = enddate - timedelta(days=daysinthepast) + + daysinthepast=daysinthepast+1 + #startdate = startdate.replace(hour=0, minute=1) + enddate = enddate.replace(hour=23, minute=59) + + + + sensordata, usedsensorlist, mintime, maxtime = sensordbmod.getAllSensorsDataPeriodv2(enddate,daysinthepast) - #Usedfor="Moisturecontrol" - #hygrosensorlist=hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR,Usedfor,hardwaremod.HW_INFO_NAME) + actuatordata,usedactuatorlist=actuatordbmod.getAllActuatorDataPeriodv2(enddate,daysinthepast) + actuatorlist=actuatordbmod.gettablelist() + # associate same number to coupled actuators and sensors actuatorlisth= autowateringdbmod.getelementlist() for inde in range(len(usedactuatorlist)): element=usedactuatorlist[inde] if element in actuatorlisth: linkedsensor=autowateringdbmod.gethygrosensorfromactuator(element) if linkedsensor in usedsensorlist: # if the actuator has an associated sensor hygro - hygroactuatornumlist.append(inde) - hygrosensornumlist.append(usedsensorlist.index(linkedsensor)) - - #select hygrometers without associated actuator + hygroactuatornumlist.append(inde) # create list with index number of the actuator + hygrosensornumlist.append(usedsensorlist.index(linkedsensor)) # create list with index of the matching sensros + + #select hygrometers in usedsensorlist with associated actuator where the actuator is not in the usedactuatorlist + # this sensor would be solid line but not associated because the actuator is not used then not in the graph + for inde in range(len(usedsensorlist)): + element=usedsensorlist[inde] + if not inde in hygrosensornumlist: + if autowateringdbmod.checkactivehygrosensor(element): # sensor is active even if the associated actuator is not present + hygrosensornumlistwithoutactive.append(inde) # create list with index number of the actuator + + #select hygrometers without associated actuator, sensorlist=hardwaremod.searchdatalist(hardwaremod.HW_INFO_MEASURE,"Moisture",hardwaremod.HW_INFO_NAME) for hygro in sensorlist: if hygro in usedsensorlist: if not usedsensorlist.index(hygro) in hygrosensornumlist: - hygrosensornumlistwithout.append(usedsensorlist.index(hygro)) + if not usedsensorlist.index(hygro) in hygrosensornumlistwithoutactive: + hygrosensornumlistwithout.append(usedsensorlist.index(hygro)) + + #select watercontrol actuator without associated hygrometer + #Usedfor="Moisturecontrol" + #hygrosensorlist=hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR,Usedfor,hardwaremod.HW_INFO_NAME) + + + # actuatorlisth is provided by autowatering + for actuator in actuatorlisth: + if actuator in usedactuatorlist: + if not usedactuatorlist.index(actuator) in hygroactuatornumlist: + actuatornumlistwithout.append(usedactuatorlist.index(actuator)) + print "hygrosensornumlist " , hygrosensornumlist print "hygroactuatornumlist " , hygroactuatornumlist - return render_template('showsensordata.html',actiontype=actiontype,periodtype=periodtype,periodlist=periodlist,usedsensorlist=usedsensorlist,sensordata=json.dumps(sensordata),usedactuatorlist=usedactuatorlist,actuatordata=json.dumps(actuatordata), hygrosensornumlist=hygrosensornumlist, hygroactuatornumlist=hygroactuatornumlist, hygrosensornumlistwithout=hygrosensornumlistwithout) + + + startdatestr=startdate.strftime(DATEFORMAT) + enddatestr=enddate.strftime(DATEFORMAT) + + print "date periods " , startdatestr , " " , enddatestr , " days ", daysinthepast + + + return render_template('showsensordata.html',actiontype=actiontype,periodtype=periodtype,periodlist=periodlist,startdatestr=startdatestr, enddatestr=enddatestr,usedsensorlist=usedsensorlist,sensordata=json.dumps(sensordata),usedactuatorlist=usedactuatorlist,actuatordata=json.dumps(actuatordata), hygrosensornumlist=hygrosensornumlist, hygroactuatornumlist=hygroactuatornumlist, hygrosensornumlistwithout=hygrosensornumlistwithout , actuatornumlistwithout=actuatornumlistwithout, hygrosensornumlistwithoutactive=hygrosensornumlistwithoutactive) @application.route('/wateringplan/' , methods=['GET', 'POST']) @@ -1425,9 +1560,9 @@ def wateringplan(): schemaementlist= advancedmod.getelementlist() - print "table --------------------------------------------------- > ", table - print "table1 --------------------------------------------------- > ", table1 - print "table2 --------------------------------------------------- > ", table2 + #print "table --------------------------------------------------- > ", table + #print "table1 --------------------------------------------------- > ", table1 + #print "table2 --------------------------------------------------- > ", table2 selectedelement = request.args.get('selectedelement') if selectedelement==None: @@ -1460,7 +1595,7 @@ def wateringplan(): dicttemp[param]=thelist wateringdbmod.replacerow(element,dicttemp) - flash('Table as been saved') + flash('Table has been saved') table=wateringdbmod.gettable(1) # watering time multiplieer table1=wateringdbmod.gettable(0) # watering schema table2=wateringdbmod.gettable(2) # watering schema @@ -1523,7 +1658,7 @@ def autowatering(): print "dicttemp ----->",dicttemp autowateringdbmod.replacerow(element,dicttemp) - flash('Table as been saved') + flash('Table has been saved') #selectedplanmod.resetmastercallback() @@ -1620,7 +1755,7 @@ def automation(): print "dicttemp ----->",dicttemp automationdbmod.replacerow(element,dicttemp) - flash('Table as been saved') + flash('Table has been saved') #selectedplanmod.resetmastercallback() @@ -1663,6 +1798,105 @@ def automation(): return render_template("automation.html", title=title,selectedelement=selectedelement,modelist=modelist,sensorlist=sensorlist,watersettinglist=watersettinglist, cyclestatuslist=cyclestatuslist, operationlist=operationlist , alertlist=alertlist, timetriggerlist=timetriggerlist) +@application.route('/interrupt/' , methods=['GET', 'POST']) +def interrupt(): + if not session.get('logged_in'): + return render_template('login.html',error=None, change=False) + title = "Auto Watering Setting" + elementlist= interruptdbmod.getelementlist() + selectedelement = request.args.get('selectedelement') + if selectedelement==None: + selectedelement=elementlist[0] + + + sensorlist=interruptdbmod.sensorlist() + print "sensorlist ",sensorlist + timetriggerlist=interruptdbmod.sensorlisttriggertime() + + + + modelist=["None","Pre-emptive Blocking", ] + sensormodelist=["Edge" , "Edge + Level"] + followupactionlist=["None", "Extend blocking state" , "Remove blocking state" , "Follow-up action" , "Extend and Follow-up" , "Remove and Follow-up" ] + formlist=["workmode", "sensor" , "sensor_mode", "actuator_output", "preemptive_period", "actionmode_afterfirst", "folloup_output", "allowedperiod" , "mailalerttype" ] + alertlist=["None", "infoandwarning", "warningonly"] + + + + if request.method == 'POST': + actiontype=request.form['actionbtn'] + print actiontype + + if actiontype == "save": + element=request.form['element'] + print "save il form...:" , element + selectedelement=element + + + #add proper formatting + dicttemp={} + dicttemp["element"]=element + dicttemp[formlist[0]]=request.form[element+'_1'] + dicttemp[formlist[1]]=request.form[element+'_2'] + dicttemp[formlist[2]]=request.form[element+'_3'] + dicttemp[formlist[3]]=request.form[element+'_4'] + dicttemp[formlist[4]]=request.form[element+'_5'] + dicttemp[formlist[5]]=request.form[element+'_6'] + dicttemp[formlist[6]]=request.form[element+'_7'] + dicttemp[formlist[7]]=[request.form[element+'_8_1'],request.form[element+'_8_2']] + dicttemp[formlist[8]]=request.form[element+'_9'] + + + + print "dicttemp ----->",dicttemp + interruptdbmod.replacerow(element,dicttemp) + flash('Table has been saved') + + #selectedplanmod.resetmastercallback() + + + if actiontype == "reset": + element=request.form['element'] + print "Reset the Cycle:" , element + selectedelement=element + interruptmod.cyclereset(element) + + + + + + + watersettinglist=[] + for element in elementlist: + watersetting=[] + watersetting.append(element) + for item in formlist: + watersetting.append(interruptdbmod.searchdata("element",element,item)) + + watersettinglist.append(watersetting) + + + cyclestatuslist=[] + for element in elementlist: + if not (element in interruptmod.AUTO_data): + interruptmod.cyclereset(element) + cyclestatus=[] + try: # in case the object is not datetime + cyclestatus.append(interruptmod.readstatus(element,"lastactiontime").strftime("%Y-%m-%d %H:%M:%S")) + except: + cyclestatus.append("") + cyclestatus.append(interruptmod.readstatus(element,"status")) + cyclestatus.append(interruptmod.readstatus(element,"actionvalue")) + cyclestatus.append(interruptmod.readstatus(element,"alertcounter")) + #{"cyclestartdate":datetime.utcnow(),"lastwateringtime":datetime.utcnow(),"cyclestatus":"done", "checkcounter":0, "alertcounter":0, "watercounter":0} + cyclestatuslist.append(cyclestatus) + + print "ready to go to html" + + + return render_template("interrupt.html", title=title,selectedelement=selectedelement,modelist=modelist,sensormodelist=sensormodelist,followupactionlist=followupactionlist,sensorlist=sensorlist,watersettinglist=watersettinglist, cyclestatuslist=cyclestatuslist, alertlist=alertlist, timetriggerlist=timetriggerlist) + + @@ -1735,7 +1969,7 @@ def fertilizerplan(): print "dicttemp ----->",dicttemp autofertilizerdbmod.replacerow(element,dicttemp) #modify autofertilizer row - flash('Table as been saved') + flash('Table has been saved') if actiontype == "advconfig": print "open advanced setting" @@ -1819,7 +2053,7 @@ def advanced(): advancedmod.replacerow(element,dicttemp) print "Table saved" - flash('Table as been saved') + flash('Table has been saved') table=advancedmod.gettable() #print "after",table @@ -1893,7 +2127,7 @@ def logout(): @application.route('/HardwareSetting/', methods=['GET', 'POST']) -def hardwaresetting(): #on the contrary of the name, this show the setting menu +def hardwaresetting(): if not session.get('logged_in'): return render_template('login.html',error=None, change=False) print "visualizzazione menu hardwareSetting:" @@ -1958,7 +2192,8 @@ def hardwaresetting(): #on the contrary of the name, this show the setting menu #scheduler setup--------------------- selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins - hardwaremod.initallGPIOoutput() + hardwaremod.initallGPIOoutput() + interruptmod.setinterruptevents() if requesttype=="edit": return hardwaresettingedit() @@ -1969,7 +2204,7 @@ def hardwaresetting(): #on the contrary of the name, this show the setting menu @application.route('/HardwareSettingedit/', methods=['GET', 'POST']) -def hardwaresettingedit(): #on the contrary of the name, this show the setting menu +def hardwaresettingedit(): if not session.get('logged_in'): return render_template('login.html',error=None, change=False) print "visualizzazione menu hardwareSettingedit:" @@ -2008,7 +2243,8 @@ def hardwaresettingedit(): #on the contrary of the name, this show the setting #scheduler setup--------------------- selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins - hardwaremod.initallGPIOoutput() + hardwaremod.initallGPIOoutput() + interruptmod.setinterruptevents() return redirect(url_for('hardwaresetting')) if requesttype=="reload": @@ -2035,6 +2271,7 @@ def hardwaresettingedit(): #on the contrary of the name, this show the setting hardwaremod.addrow(dictrow) flash('Row has been correctly Added') ret_data = {"answer":"Added"} + hardwaremod.IOdatarow[hardwaremod.HW_INFO_NAME]="" else: print "problem ", message flash(message,'danger') @@ -2068,14 +2305,15 @@ def hardwaresettingeditfield(): if request.method == 'POST': requestinfo=request.form['buttonsub'] requesttype=requestinfo.split("_")[0] - print "requesttype POST " , requestinfo , " " , requesttype + print "hardwaresettingeditfield requesttype POST " , requestinfo , " " , requesttype - if requestinfo=="edit": + #if requestinfo=="editnames": #request coming from previous page, need init table from zero - print "the teporary Tables have been reset" - + #print "the teporary Tables have been reset" # Alignt the hardwaremod IOdatatemp to IOdata - hardwaremod.IOdatatempalign() + #hardwaremod.IOdatatempalign() + + if requesttype=="confirm": @@ -2098,14 +2336,19 @@ def hardwaresettingeditfield(): wateringdbmod.replacewordandsave(oldnames,newnames) autofertilizerdbmod.replacewordandsave(oldnames,newnames) fertilizerdbmod.replacewordandsave(oldnames,newnames) - automationdbmod.replacewordandsave(oldnames,newnames) + automationdbmod.replacewordandsave(oldnames,newnames) + interruptdbmod.replacewordandsave(oldnames,newnames) sensordbmod.consistencycheck() actuatordbmod.consistencycheck() #scheduler setup--------------------- selectedplanmod.resetmastercallback() #initiate the GPIO OUT pins hardwaremod.initallGPIOoutput() + interruptmod.setinterruptevents() return redirect(url_for('show_Calibration')) + else: + # Alignt the hardwaremod IOdatatemp to IOdata + hardwaremod.IOdatatempalign() if requesttype=="reload": hardwaremod.IOdatatempalign() @@ -2142,7 +2385,7 @@ def HWsettingEditAjax(): IOname=pk if IOname=="addrow": - dictrow=hardwaremod.IOdatarow + dictrow=hardwaremod.deepcopydict(hardwaremod.IOdatarow) else: dictrow=hardwaremod.searchrowtempbyname(IOname) dictrow[name]=value @@ -2165,6 +2408,7 @@ def HWsettingEditAjax(): isfound=hardwaremod.changeIOdatatemp(IOname,name,value) #print "item found " , isfound + print "IOdatarow: " , hardwaremod.IOdatarow #print "IOdatatemp: " , hardwaremod.IOdatatemp @@ -2184,34 +2428,47 @@ def currentpath(filename): def functiontest(): print " testing " + #mailname="mail1" #testo=[" riga 1 ", "riga 2 " , " Riga fine"] #emailmod.sendallmail("alert","prova mail", testo) - #autofertilizermod.AUTO_data["doser1"]["tobeactivated"]=True - #autofertilizermod.AUTO_data["doser1"]["duration"]=5000 - #autowateringmod.activatewater("water2", 50000) + + + filemanagementmod.configfilezip() + + #import statusdataDBmod + #statusdataDBmod.write_status_data(autofertilizermod.AUTO_data,"doser1","tobeactivated",True) + #statusdataDBmod.write_status_data(autofertilizermod.AUTO_data,"doser1","duration",5) + #autowateringmod.activatewater("water1", 50) + + #target="doser1" + #activationseconds="10" + #selectedplanmod.pulsenutrient(target,activationseconds) #startdate=datetime.strptime('Sep 7 2018 5:00AM', '%b %d %Y %I:%M%p') #enddate=datetime.strptime('Sep 7 2018 8:00AM', '%b %d %Y %I:%M%p') #slopeOK=autowateringmod.checkinclination("hygroBalcFront",startdate,enddate) #print "got array " , slopeOK - selectedplanmod.heartbeat() + #selectedplanmod.heartbeat() #target="water1" #selectedplanmod.startpump(target,"30","10","5") #selectedplanmod.removeallscheduledjobs() - #hardwaremod.takephoto() + #isok=hardwaremod.takephoto() + #hostname=networkmod.gethostname() #refsensor="TimeTrigger" - #element="water1234567" + #element="water2" #automationmod.automationexecute(refsensor,element) - #automationmod.automationcheck("TimeTrigger") + + #isok, quantity = automationmod.sensorreading("pressuresensor1",5,"average") + #print "isok " , isok , " quantity " , quantity + #message = quantity - message = "ok" - return message + return "" # video part ---------------------------------- hello ------------------------------- import videocontrolmod @@ -2225,7 +2482,10 @@ def videostream(): ipaddress=networkmod.get_local_ip() videolist=hardwaremod.videodevlist() servolist=hardwaremod.searchdatalist(hardwaremod.HW_CTRL_CMD,"servo",hardwaremod.HW_INFO_NAME) - initposition=hardwaremod.getservopercentage(servolist[0]) + if servolist: + initposition=hardwaremod.getservopercentage(servolist[0]) + else: + initposition="" vdirection=hardwaremod.searchdata(hardwaremod.HW_FUNC_USEDFOR,"photocontrol",hardwaremod.HW_CTRL_LOGIC) if vdirection=="neg": rotdeg="180" diff --git a/static/filestyle123/bootstrap-filestyle.min.js b/static/filestyle123/bootstrap-filestyle.min.js new file mode 100644 index 0000000..9aa702c --- /dev/null +++ b/static/filestyle123/bootstrap-filestyle.min.js @@ -0,0 +1,10 @@ +/* + * bootstrap-filestyle + * doc: http://markusslima.github.io/bootstrap-filestyle/ + * github: https://github.com/markusslima/bootstrap-filestyle + * + * Copyright (c) 2017 Markus Vinicius da Silva Lima + * Version 1.2.3 + * Licensed under the MIT license. + */ +!function(t){"use strict";var e=0,i=function(e,i){this.options=i,this.$elementFilestyle=[],this.$element=t(e)};i.prototype={clear:function(){this.$element.val(""),this.$elementFilestyle.find(":text").val(""),this.$elementFilestyle.find(".badge").remove()},destroy:function(){this.$element.removeAttr("style").removeData("filestyle"),this.$elementFilestyle.remove()},disabled:function(t){if(!0===t)this.options.disabled||(this.$element.attr("disabled","true"),this.$elementFilestyle.find("label").attr("disabled","true"),this.options.disabled=!0);else{if(!1!==t)return this.options.disabled;this.options.disabled&&(this.$element.removeAttr("disabled"),this.$elementFilestyle.find("label").removeAttr("disabled"),this.options.disabled=!1)}},buttonBefore:function(t){if(!0===t)this.options.buttonBefore||(this.options.buttonBefore=!0,this.options.input&&(this.$elementFilestyle.remove(),this.constructor(),this.pushNameFiles()));else{if(!1!==t)return this.options.buttonBefore;this.options.buttonBefore&&(this.options.buttonBefore=!1,this.options.input&&(this.$elementFilestyle.remove(),this.constructor(),this.pushNameFiles()))}},icon:function(t){if(!0===t)this.options.icon||(this.options.icon=!0,this.$elementFilestyle.find("label").prepend(this.htmlIcon()));else{if(!1!==t)return this.options.icon;this.options.icon&&(this.options.icon=!1,this.$elementFilestyle.find(".icon-span-filestyle").remove())}},input:function(t){if(!0===t)this.options.input||(this.options.input=!0,this.options.buttonBefore?this.$elementFilestyle.append(this.htmlInput()):this.$elementFilestyle.prepend(this.htmlInput()),this.$elementFilestyle.find(".badge").remove(),this.pushNameFiles(),this.$elementFilestyle.find(".group-span-filestyle").addClass("input-group-btn"));else{if(!1!==t)return this.options.input;if(this.options.input){this.options.input=!1,this.$elementFilestyle.find(":text").remove();var e=this.pushNameFiles();e.length>0&&this.options.badge&&this.$elementFilestyle.find("label").append(' '+e.length+""),this.$elementFilestyle.find(".group-span-filestyle").removeClass("input-group-btn")}}},size:function(t){if(void 0===t)return this.options.size;var e=this.$elementFilestyle.find("label"),i=this.$elementFilestyle.find("input");e.removeClass("btn-lg btn-sm"),i.removeClass("input-lg input-sm"),"nr"!=t&&(e.addClass("btn-"+t),i.addClass("input-"+t))},placeholder:function(t){if(void 0===t)return this.options.placeholder;this.options.placeholder=t,this.$elementFilestyle.find("input").attr("placeholder",t)},buttonText:function(t){if(void 0===t)return this.options.buttonText;this.options.buttonText=t,this.$elementFilestyle.find("label .buttonText").html(this.options.buttonText)},buttonName:function(t){if(void 0===t)return this.options.buttonName;this.options.buttonName=t,this.$elementFilestyle.find("label").attr({class:"btn "+this.options.buttonName})},iconName:function(t){if(void 0===t)return this.options.iconName;this.$elementFilestyle.find(".icon-span-filestyle").attr({class:"icon-span-filestyle "+this.options.iconName})},htmlIcon:function(){return this.options.icon?' ':""},htmlInput:function(){return this.options.input?' ':""},pushNameFiles:function(){var t="",e=[];void 0===this.$element[0].files?e[0]={name:this.$element[0]&&this.$element[0].value}:e=this.$element[0].files;for(var i=0;i",n=i.options.buttonBefore?l+i.htmlInput():i.htmlInput()+l,i.$elementFilestyle=t('
'+n+"
"),i.$elementFilestyle.find(".group-span-filestyle").attr("tabindex","0").keypress(function(t){if(13===t.keyCode||32===t.charCode)return i.$elementFilestyle.find("label").click(),!1}),i.$element.css({position:"absolute",clip:"rect(0px 0px 0px 0px)"}).attr("tabindex","-1").after(i.$elementFilestyle),(i.options.disabled||i.$element.attr("disabled"))&&i.$element.attr("disabled","true"),i.$element.change(function(){var t=i.pushNameFiles();0==i.options.input&&i.options.badge?0==i.$elementFilestyle.find(".badge").length?i.$elementFilestyle.find("label").append(' '+t.length+""):0==t.length?i.$elementFilestyle.find(".badge").remove():i.$elementFilestyle.find(".badge").html(t.length):i.$elementFilestyle.find(".badge").remove()}),window.navigator.userAgent.search(/firefox/i)>-1&&i.$elementFilestyle.find("label").click(function(){return i.$element.click(),!1})}};var n=t.fn.filestyle;t.fn.filestyle=function(e,n){var s="",l=this.each(function(){if("file"===t(this).attr("type")){var l=t(this),o=l.data("filestyle"),a=t.extend({},t.fn.filestyle.defaults,e,"object"==typeof e&&e);o||(l.data("filestyle",o=new i(this,a)),o.constructor()),"string"==typeof e&&(s=o[e](n))}});return void 0!==typeof s?s:l},t.fn.filestyle.defaults={buttonText:"Choose file",iconName:"glyphicon glyphicon-folder-open",buttonName:"btn-default",size:"nr",input:!0,badge:!0,icon:!0,buttonBefore:!1,disabled:!1,placeholder:""},t.fn.filestyle.noConflict=function(){return t.fn.filestyle=n,this},t(function(){t(".filestyle").each(function(){var e=t(this),i={input:"false"!==e.attr("data-input"),icon:"false"!==e.attr("data-icon"),buttonBefore:"true"===e.attr("data-buttonBefore"),disabled:"true"===e.attr("data-disabled"),size:e.attr("data-size"),buttonText:e.attr("data-buttonText"),buttonName:e.attr("data-buttonName"),iconName:e.attr("data-iconName"),badge:"false"!==e.attr("data-badge"),placeholder:e.attr("data-placeholder")};e.filestyle(i)})})}(window.jQuery); \ No newline at end of file diff --git a/statusdataDBmod.py b/statusdataDBmod.py index 4049ed5..8233022 100644 --- a/statusdataDBmod.py +++ b/statusdataDBmod.py @@ -8,7 +8,6 @@ def read_status_data(data,element,variable): - print data if element in data: print " element present" elementdata=data[element] diff --git a/templates/ShowCalibration.html b/templates/ShowCalibration.html index a884feb..db445c2 100644 --- a/templates/ShowCalibration.html +++ b/templates/ShowCalibration.html @@ -2,6 +2,10 @@ {% set active_page = "showcalibration" %} {% block body %} {% if session.logged_in %} + + + +
@@ -223,7 +227,6 @@

Actuators Test

-
@@ -284,8 +287,8 @@

Actuators Test

if (!answer.includes("Stopped")) { $('#' + elem + "progress" ).css('width', '0%').attr('aria-valuenow', 0); $('#' + elem + "progress").text('0') - } - } + } + } } @@ -320,12 +323,12 @@

Actuators Test

-
+ + + + +
+
+
+ +
+
+ +
send by email the info plus warning or the warning only
+ +
+
+
+ + + + + +
+
+
+ System Current Status +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Last ActivationStatusActuator ValueWarning
+
{{ cyclestatuslist[loop.index0][0] }}
+
+
{{ cyclestatuslist[loop.index0][1] }}
+
+
{{ cyclestatuslist[loop.index0][2] }}
+
+
{{ cyclestatuslist[loop.index0][3] }}
+
+ +
+
+ + + +
+ +
+ +
+
+ +
+ + +
+ +
+ + + + + + + + + + + + + {% endfor %} + + + + + +{% else %} + +
+
+

Sensor not available

+ +
+
+ + +{% endif %} + + + + + + + + + + + + {% else %} + +

Please log in

+ + + {% endif %} + + + +{% endblock %} diff --git a/templates/layout.html b/templates/layout.html index 06c4def..cec337e 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -67,6 +67,7 @@ ('/autowatering/', 'autowatering', 'AutoWatering'), ('/fertilizerplan/', 'fertilizerplan', 'FertilizerPlan'), ('/automation/', 'automation', 'Automation'), + ('/interrupt/', 'interrupt', 'Interrupt'), ('/ShowCalibration/', 'showcalibration', 'Settings'), ('/network/', 'network', 'Network'), ('/HardwareSetting/', 'HardwareSetting', 'HardwareSetting'), diff --git a/templates/network.html b/templates/network.html index 547188b..e247595 100644 --- a/templates/network.html +++ b/templates/network.html @@ -4,28 +4,32 @@ {% if session.logged_in %} - - - - -
+

Connection parameters

+ +
+

Local IP address: {{iplocalwifi}}

+

IP PORT: {{ipport}}

+

+

LocalHost: {{hostname}}

+

URL for LOCAL connection: {{hostname}}.local:{{ipport}}

+

+ {% for ipaddr in iplocallist %} +

URL for LOCAL Connection: {{ipaddr}}:{{ipport}}

+ {% endfor %} - - {% if localwifisystem==connectedssid %} -

Connected IP address {{iplocal}} -

IP address of the WiFi Acces point of this system {{iplocalwifi}} - IP PORT {{ipport}} + {% if localwifisystem == connectedssid %} {% else %} -

Local IP address for router setting {{iplocal}} - IP PORT for router setting {{ipport}} +

+

In case of port forwarding enableb on your router

+

URL for REMOTE Connection: {{ipext}}:{{ipport}}

{% endif %} - +
+
+
+ + - - - + @@ -71,7 +84,7 @@

Local IP address

- + diff --git a/templates/networksetting.html b/templates/networksetting.html index 855e41f..be659b1 100644 --- a/templates/networksetting.html +++ b/templates/networksetting.html @@ -2,18 +2,11 @@ {% block body %} {% if session.logged_in %} - +
-
-
- -
-
@@ -21,16 +14,15 @@
-
-
+
Parameters Setting
-
+
-
+
@@ -39,12 +31,11 @@
IP address for local connection
-
+
-
@@ -52,11 +43,9 @@
-
-
@@ -64,14 +53,12 @@
-
-
@@ -81,7 +68,7 @@
{% set arr=["0","60","120","180","240","300"] %} - {% for item in arr %} {% endfor %} @@ -93,18 +80,41 @@
When the system is started, this valuse indicated the time in seconds that the Access point is ON before the WiFi netowrk is connectred (if configured)
+
+
+ + +
+
+
-
+ + +
+ + + +
Hostname is set to easily reach the system when using local network, To be effecetive, after clicking the saving button, the system should be restarted
+ +
+ + + + + + + + +
-
+
- -
+
@@ -113,6 +123,7 @@ +
{% endif %} diff --git a/templates/setstepper.html b/templates/setstepper.html index acfbbcd..ab5e8c4 100644 --- a/templates/setstepper.html +++ b/templates/setstepper.html @@ -12,7 +12,7 @@

Stepper Actuators Test

-
+
diff --git a/templates/showimages.html b/templates/showimages.html index 90cb09c..4b7f2ac 100644 --- a/templates/showimages.html +++ b/templates/showimages.html @@ -190,11 +190,14 @@

Delete All Images

$(".thumbnail").click(function() { var selvalue=$(this).attr('index'); // define options (if needed) - var options = { + var options = { // optionName: 'option value' // for example: index: parseInt(selvalue), // start at first slide - clickToCloseNonZoomable: false + clickToCloseNonZoomable: false, + shareButtons: [ + {id:'download', label:'Download image', url:'{{raw_image_url}}', download:true} + ], }; var gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options); gallery.init(); diff --git a/templates/showsensordata.html b/templates/showsensordata.html index c7ac5b1..3a78f22 100644 --- a/templates/showsensordata.html +++ b/templates/showsensordata.html @@ -446,7 +446,14 @@ var hygrosensornumlist={{hygrosensornumlist}}; var hygroactuatornumlist={{hygroactuatornumlist}}; var hygrosensornumlistwithout={{hygrosensornumlistwithout}}; - var seriesColors= [ "#4bb2c5", "#c5b47f", "#EAA228", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc"] + var actuatornumlistwithout={{actuatornumlistwithout}}; + var hygrosensornumlistwithoutactive={{hygrosensornumlistwithoutactive}} + //var seriesColors= [ "#4bb2c5", "#c5b47f", "#EAA228", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc"] + + //var seriesColors= [ "#e6194B", "#3cb44b", "#ffe119", "#4363d8", "#f58231", "#911eb4", "#42d4f4", "#f032e6", "#bfef45", "#469990", "#e6beff", "#9A6324", "#fffac8", "#800000", "#aaffc3", "#808000", "#ffd8b1", "#000075", "#a9a9a9", "#000000"] + + var seriesColors= [ "#2d89ef", "#2b5797", "#ffc40d", "#e3a21a", "#da532c", "#ee1111", "#b91d47", "#99b433", "#00a300", "#1e7145", "#ff0097", "#9f00a7", "#7e3878", "#603cba", "#1d1d1d", "#00aba9", "#000000"] + var fLen, i, seriedict; var sensorseriesh=[]; @@ -468,7 +475,17 @@ sensorchartdatah.push(sensorchartdata[hygrosensornumlistwithout[i]]); } + var continu_i=continu_i+fLen // keep incremnting the number to avoid same colors + fLen = hygrosensornumlistwithoutactive.length; + for (i = 0; i < fLen; i++) { + + seriedict={"label": sensorlist[hygrosensornumlistwithoutactive[i]], "color":seriesColors[(continu_i+i) % seriesColors.length] , "showLine":true, "linePattern" : 'solid', "yaxis" : 'yaxis', "markerOptions" : { "style": "filledCircle", "size": 1 }}; + sensorseriesh.push(seriedict); + sensorchartdatah.push(sensorchartdata[hygrosensornumlistwithoutactive[i]]); + } + var continu_i=continu_i+fLen // keep incremnting the number to avoid same colors + var fLen, i, seriedict; var actuatorseriesh=[]; @@ -479,7 +496,14 @@ actuatorseriesh.push(seriedict); actuatorchartdatah.push(actuatorchartdata[hygroactuatornumlist[i]]); } - + + // actuators without , smaller size + fLen = actuatornumlistwithout.length; + for (i = 0; i < fLen; i++) { + seriedict={"label": actuatorlist[actuatornumlistwithout[i]], "color":seriesColors[(continu_i+i) % seriesColors.length] , "showLine":false, "yaxis" : 'y2axis', "markerOptions" : { "style": shapes[(continu_i+i) % shapes.length] , "size": 8 }}; + actuatorseriesh.push(seriedict); + actuatorchartdatah.push(actuatorchartdata[actuatornumlistwithout[i]]); + } var combochartseriesh = actuatorseriesh.concat(sensorseriesh); @@ -708,7 +732,7 @@

Data Trend

- + +
+
+
+
+ + + + +
+
+
+
+
+
+ + + + +
+
+
+
+
+ +
+
+
+ @@ -810,7 +882,7 @@

Data Trend

- {% if (hygrosensornumlist|length + hygroactuatornumlist|length + hygrosensornumlistwithout|length)>0%} + {% if (hygrosensornumlist|length + hygroactuatornumlist|length + hygrosensornumlistwithout|length + hygrosensornumlistwithoutactive|length + actuatornumlistwithout|length)>0 %}
Auto water Control Chart
@@ -859,6 +931,9 @@

Delete Data Record

$('#' + idref).attr("value", selvalue); }); }); + + + diff --git a/templates/videostream.html b/templates/videostream.html index e3f8125..1258767 100644 --- a/templates/videostream.html +++ b/templates/videostream.html @@ -4,9 +4,12 @@ {% if session.logged_in %} -
+ +
+ {% if videolist|length > 0 %} +
@@ -75,11 +78,14 @@ {% endfor %} + @@ -97,7 +103,9 @@ @@ -110,7 +118,7 @@
- + - +
- + {% endif %} @@ -192,9 +200,10 @@