Skip to content

Commit

Permalink
Merge pull request #2 from vingerha/0.1.1
Browse files Browse the repository at this point in the history
0.1.1
  • Loading branch information
vingerha authored Mar 21, 2022
2 parents e54b5e2 + c6a3a83 commit 98dc477
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 53 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The integration will create a device per student/user and sensors for
- Evaluation (Note: Evaluation is replacing Grade over time, i.e. 'mentions' instead of grade-values)
The sensors can be made visible in Home Assistant using the markdown-card, an example is included. (https://github.com/vingerha/pronote2mqtt/blob/main/example_markdown.yaml)
![image](https://user-images.githubusercontent.com/44190435/154719453-895ee43e-2f27-41e5-8000-76c346ca0579.png)

In HA automations, one can add a notification that will send a app-message if updated, this example show last 2 evaluations: (https://github.com/vingerha/pronote2mqtt/blob/main/example_notification.yaml)


## About
Expand All @@ -35,8 +35,8 @@ The sensors can be made visible in Home Assistant using the markdown-card, an ex

1. Install directly from docker : `docker pull vingerha/pronote2mqtt:latest`
It is recommended to map the volumes 'app' and 'data' so one can access these easier.
The python files must be copied into the 'app' folder.
The 'data' folder will contain the sqlite3 database: pronote2mqtt.db
The docker entryscsript will ensure that the files are copied into that volumne and will (should) not overrride existin param.py or ent.py as these are used for local config. In exceptional cases, the python files must be manually copied into the 'app' folder (please send me any use-case as 'issue')
The 'data' folder will contain the sqlite3 database: pronote2mqtt.db, then you can access its data with e.g. 'DB Browser for SQLite'.
2. Update the params.py with your values to connect to MQTT and pronote.
3. Update ent.py. I have added an ent.py based on the one by pronotepy. The package currently assumes that you are accessing over CAS (as do most students), so make sure that ent.py has your specific CAS properly setup...for details check pronotepy on how to update your CAS in ent.py.

Expand All @@ -58,7 +58,7 @@ Or from commandline, in the folder where you stored the files form /app, using t

### Long Term Usage

Pronote2mqtt will try and reconnect at fixed times (param.py default: 10:00). It depends on pronotepy so cannot assure that it will continue to be working.
Pronote2mqtt will try and reconnect at fixed times (param.py default: 06:00). It depends on pronotepy so cannot assure that it will continue to be working.

## Contributing

Expand Down
11 changes: 7 additions & 4 deletions app/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ def init(self,p2mVersion,dbVersion):
, lessonRoom TEXT
, lessonCanceled TEXT
, lessonStatus TEXT
, PRIMARY KEY(studentname,lessonDateTime,lessonSubject))''')
self.cur.execute('''CREATE UNIQUE INDEX IF NOT EXISTS idx_lessons_lid
ON lessons (studentname,lessonDateTime,LessonSubject)''')
, PRIMARY KEY(studentname,lessonDateTime,lessonSubject,lessonRoom, lessonCanceled))''')
# self.cur.execute('''CREATE UNIQUE INDEX IF NOT EXISTS idx_lessons_lid
# ON lessons (studentname,lessonDateTime,LessonSubject, lessonStatus)''')

# using key on period id and evalid
logging.debug("Creation of Homework table")
Expand Down Expand Up @@ -382,7 +382,10 @@ def _loadStudents(self):
# Load homework
def _loadHomework(self,student):
studentname=student.studentFullname
query = f"SELECT * FROM homework WHERE studentname = '{studentname}' order by homeworkDate"
datestart = datetime.date.today().strftime("%Y/%m/%d")
dateend = datetime.date.today() + relativedelta(days=7)
dateend = dateend.strftime("%Y/%m/%d")
query = f"SELECT * FROM homework WHERE studentname = '{studentname}' and homeworkDate between '{datestart}' and '{dateend}' order by homeworkDate"
self.cur.execute(query)
queryResult = self.cur.fetchall()
# Create object Homework
Expand Down
23 changes: 9 additions & 14 deletions app/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ def __init__(self):
self.mqttSsl = False


# Run params
# Run params, scheduleFrequency (in hours) will take precendce over scheduleTime, if none or set then only 1 run.
self.scheduleTime = '06:00'
self.scheduleFrequency = 2

# Publication params
self.hassDiscovery = True
Expand All @@ -75,8 +76,6 @@ def __init__(self):
def initArg(self):

self.parser = argparse.ArgumentParser()
self.parser.add_argument(
"--pronote_student_1", help="PRONOTE student name, ex : 'name'")
self.parser.add_argument(
"--pronote_username_1", help="PRONOTE user name, ex : 'first.last'")
self.parser.add_argument(
Expand All @@ -88,8 +87,6 @@ def initArg(self):
self.parser.add_argument(
"--pronote_cas_1", help="PRONOTE case")

self.parser.add_argument(
"--pronote_student_2", help="PRONOTE student name, ex : 'name'")
self.parser.add_argument(
"--pronote_username_2", help="PRONOTE user name, ex : myemail@email.com")
self.parser.add_argument(
Expand All @@ -102,7 +99,9 @@ def initArg(self):
"--pronote_cas_2", help="PRONOTE case")

self.parser.add_argument(
"-s", "--schedule", help="Schedule the launch of the script at hh:mm everyday")
"--schedule_time", help="Schedule the launch of the script at hh:mm everyday")
self.parser.add_argument(
"--schedule_frequency", help="Schedule the launch of the script very X hours")
self.parser.add_argument(
"--mqtt_host", help="Hostname or ip adress of the Mqtt broker")
self.parser.add_argument(
Expand Down Expand Up @@ -141,14 +140,12 @@ def initArg(self):
# Get params from arguments in command line
def getFromArgs(self):

if self.args.pronote_student_1 is not None: self.pronoteStudent_1 = self.args.pronote_student_1
if self.args.pronote_username_1 is not None: self.pronoteUsername_1 = self.args.pronote_username_1
if self.args.pronote_password_1 is not None: self.pronotePassword_1 = self.args.pronote_password_1
if self.args.pronote_prefixurl_1 is not None: self.pronotePrefixUrl_1 = self.args.pronote_prefixurl_1
if self.args.pronote_ent_1 is not None: self.pronoteEnt_1 = self.args.pronote_end_1
if self.args.pronote_cas_1 is not None: self.pronotePassword_1 = self.args.pronote_cas_1

if self.args.pronote_student_2 is not None: self.pronoteStudent_2 = self.args.pronote_student_2
if self.args.pronote_username_2 is not None: self.pronoteUsername_2 = self.args.pronote_username_2
if self.args.pronote_password_2 is not None: self.pronotePassword_2 = self.args.pronote_password_2
if self.args.pronote_prefixurl_2 is not None: self.pronotePrefixUrl_2 = self.args.pronote_prefixurl_2
Expand All @@ -166,8 +163,8 @@ def getFromArgs(self):
if self.args.mqtt_retain is not None: self.mqttRetain = _isItTrue(self.args.mqtt_retain)
if self.args.mqtt_ssl is not None: self.mqttSsl = _isItTrue(self.args.mqtt_ssl)

if self.args.schedule is not None: self.scheduleTime = self.args.schedule
if self.args.schedule_time is not None: self.scheduleTime = self.args.schedule_time
if self.args.schedule_frequency is not None: self.scheduleFrequency = self.args.schedule_frequency

if self.args.hass_discovery is not None: self.hassDiscovery = _isItTrue(self.args.hass_discovery)
if self.args.hass_prefix is not None: self.hassPrefix = self.args.hass_prefix
Expand All @@ -181,10 +178,7 @@ def getFromArgs(self):

# Check parameters
def checkParams(self):
if self.pronoteStudent_1 is None:
logging.error("Parameter PRONOTE username is mandatory.")
return False
elif self.pronoteUsername_1 is None:
if self.pronoteUsername_1 is None:
logging.error("Parameter PRONOTE username is mandatory.")
return False
elif self.pronotePassword_1 is None:
Expand Down Expand Up @@ -220,3 +214,4 @@ def logParams(self):

logging.info("Database options : Force reinitialization = %s, Path = %s", self.dbInit, self.dbPath)
logging.info("Debug mode : Enable = %s", self.debug)

79 changes: 48 additions & 31 deletions app/pronote2mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def run(myParams):
attributes[f'done'] = []
for myHomework in myStudent.homeworkList:
# Store homework into sensor
attributes[f'date'].append(myHomework.homeworkDate.split("/",1)[1])
attributes[f'date'].append(myHomework.homeworkDate)
attributes[f'title'].append(myHomework.homeworkSubject)
attributes[f'description'].append(re.sub(r'http\S+', '<URL REMOVED, see PRONOTE-APP>', myHomework.homeworkDescription))
attributes[f'done'].append(myHomework.homeworkDone)
Expand All @@ -284,7 +284,7 @@ def run(myParams):
attributes[f'acquisition_level'] = []
for myEvaluation in myStudent.evaluationShortList:
# Store evaluation into sensor
attributes[f'date'].append(myEvaluation.evalDate.split("/",1)[1])
attributes[f'date'].append(myEvaluation.evalDate)
attributes[f'subject'].append(myEvaluation.evalSubject)
attributes[f'acquisition_name'].append(myEvaluation.acqName)
attributes[f'acquisition_level'].append(myEvaluation.acqLevel)
Expand Down Expand Up @@ -374,7 +374,7 @@ def run(myParams):
attributes[f'comment'] = []
for myGrade in myStudent.gradeList:
# Store evaluation into sensor
attributes[f'date'].append(myGrade.date.split("/",1)[1])
attributes[f'date'].append(myGrade.date)
attributes[f'subject'].append(myGrade.subject)
attributes[f'student_grade'].append(myGrade.defaultOutOf)
attributes[f'class_average'].append(myGrade.average)
Expand Down Expand Up @@ -411,7 +411,7 @@ def run(myParams):
attributes[f'room'] = []
for myLesson in myStudent.lessonShortList:
# Store evaluation into sensor
attributes[f'date'].append(myLesson.lessonDateTime.split("/",1)[1])
attributes[f'date'].append(myLesson.lessonDateTime.split(" ",1)[0])
attributes[f'start'].append(myLesson.lessonStart)
attributes[f'end'].append(myLesson.lessonEnd)
attributes[f'subject'].append(myLesson.lessonSubject)
Expand Down Expand Up @@ -445,18 +445,18 @@ def run(myParams):
####################################################################################################################
# STEP 4 : Disconnect mqtt broker (throws errors....to fix in future)
####################################################################################################################
# if myMqtt.isConnected:
#
# logging.info("-----------------------------------------------------------")
# logging.info("# Disconnexion from MQTT #")
# logging.info("-----------------------------------------------------------")
#
# try:
# myMqtt.disconnect()
# logging.info("Mqtt broker disconnected")
# except:
# logging.error("Unable to disconnect mqtt broker")
# sys.exit(1)
if myMqtt.isConnected:

logging.info("-----------------------------------------------------------")
logging.info("# Disconnexion from MQTT #")
logging.info("-----------------------------------------------------------")

try:
myMqtt.disconnect()
logging.info("Mqtt broker disconnected")
except:
logging.error("Unable to disconnect mqtt broker")
sys.exit(1)

# Release memory
del myMqtt
Expand All @@ -482,10 +482,14 @@ def run(myParams):
logging.info("-----------------------------------------------------------")
logging.info("# Next run #")
logging.info("-----------------------------------------------------------")
if myParams.scheduleTime is not None:
logging.info("The pronote2mqtt next run is scheduled at %s",myParams.scheduleTime)
if myParams.scheduleFrequency > 0:
logging.info("The pronote2mqtt runs are scheduled every => %s hours",myParams.scheduleFrequency)
else:
logging.info("No schedule defined.")
if myParams.scheduleTime is not None:
logging.info("The pronote2mqtt next run is scheduled at %s",myParams.scheduleTime)

else:
logging.info("No schedule or frequency defined.")


logging.info("-----------------------------------------------------------")
Expand Down Expand Up @@ -534,21 +538,34 @@ def run(myParams):
logging.error("Error on parameters. End of program.")
quit()


# Run
if myParams.scheduleTime is not None:



# if scheduleFrequency set
if myParams.scheduleFrequency is not None:
# Run once at lauch
run(myParams)

# Then run at scheduled time
schedule.every().day.at(myParams.scheduleTime).do(run,myParams)

schedule.every(myParams.scheduleFrequency).hours.do(run,myParams)
while True:
schedule.run_pending()
time.sleep(1)
schedule.run_pending()
time.sleep(1)

else:
# if scheduleTime set
if myParams.scheduleTime is not None:
# Run once at lauch
run(myParams)
schedule.every().day.at(myParams.scheduleTime).do(run,myParams)

else:
while True:
schedule.run_pending()
time.sleep(1)

# Run once
run(myParams)
logging.info("End of pronote2mqtt.")
else:
# Run once
run(myParams)
logging.info("End of pronote2mqtt.")


26 changes: 26 additions & 0 deletions example_notification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
alias: Demo grade update
description: ''
trigger:
- platform: state
entity_id: sensor.pronote_parent_fanny_evaluation
condition: []
action:
- service: notify.mobile_[your_mobile]
data:
message: >-
'Demo' {{
state_attr('sensor.pronote_parent_fanny_evaluation','date')[0] }}
- {{
state_attr('sensor.pronote_parent_fanny_evaluation','acquisition_level')[0]
}} - {{
state_attr('sensor.pronote_parent_fanny_evaluation','subject')[0]
}}
{{- '\n' -}}
'Demo' {{
state_attr('sensor.pronote_parent_fanny_evaluation','date')[1] }}
- {{
state_attr('sensor.pronote_parent_fanny_evaluation','acquisition_level')[1]
}} - {{
state_attr('sensor.pronote_parent_fanny_evaluation','subject')[1]
}}
mode: single

0 comments on commit 98dc477

Please sign in to comment.