Skip to content

Commit

Permalink
add interrupt and bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydrosys4 committed Jul 12, 2019
1 parent 31e1dd8 commit e696101
Show file tree
Hide file tree
Showing 40 changed files with 2,493 additions and 339 deletions.
43 changes: 28 additions & 15 deletions HWcontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand All @@ -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])
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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<maxwait):
time.sleep(waitstep)
waittime=waittime+waitstep
# following instructions have been removed as in case there is cuncurrency, then better not to wait, automation will eventually repeat the command
#waitstep=0.1
#waittime=0
#maxwait=2.5
#while (read_status_data(stepper_data,Interface,"busyflag")==True)and(waittime<maxwait):
# time.sleep(waitstep)
# waittime=waittime+waitstep


print "Stepper wait time -----> ", 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
Expand All @@ -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)
Expand Down
22 changes: 15 additions & 7 deletions actuatordbmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=[]
Expand Down Expand Up @@ -163,12 +164,12 @@ def RemoveActuatorDataPeriod(removebeforedays):

# sensor data --------------------------------------------






def EvaluateDataPeriod(sensordata,startdate,enddate):
# sensor data --------------------------------------------
isok=False
outputdata={}
summa=0
inde=0
Expand All @@ -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
Expand All @@ -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 --------------------------------------------
Expand Down Expand Up @@ -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"])))

Expand Down
4 changes: 4 additions & 0 deletions autofertilizerdbmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
# filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue)
# filestoragemod.deletefile(filename)

def readfromfile():
global WTdata
filestoragemod.readfiledata(WTDATAFILENAME,WTdata)


def consistencycheck():

Expand Down
30 changes: 19 additions & 11 deletions autofertilizermod.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down
12 changes: 11 additions & 1 deletion automationdbmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
# filestoragemod.savechange(filename,searchfield,searchvalue,fieldtochange,newvalue)
# filestoragemod.deletefile(filename)

def readfromfile():
global WTdata
filestoragemod.readfiledata(WTDATAFILENAME,WTdata)


def consistencycheck():

Expand Down Expand Up @@ -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():
Expand Down
50 changes: 26 additions & 24 deletions automationmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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


Expand Down
Loading

0 comments on commit e696101

Please sign in to comment.