Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

169 lignes
6.8KB

  1. from flask import json, request
  2. from flask_classy import FlaskView, route
  3. from git import Repo, Git
  4. import sqlite3
  5. from modules.app_config import cbpi
  6. from werkzeug.utils import secure_filename
  7. import pprint
  8. import time
  9. import os
  10. from modules.steps import Step,StepView
  11. import xml.etree.ElementTree
  12. class BeerXMLImport(FlaskView):
  13. BEER_XML_FILE = "./upload/beer.xml"
  14. @route('/', methods=['GET'])
  15. def get(self):
  16. if not os.path.exists(self.BEER_XML_FILE):
  17. self.api.notify(headline="File Not Found", message="Please upload a Beer.xml File",
  18. type="danger")
  19. return ('', 404)
  20. result = []
  21. e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
  22. result = []
  23. for idx, val in enumerate(e.findall('RECIPE')):
  24. result.append({"id": idx+1, "name": val.find("NAME").text})
  25. return json.dumps(result)
  26. def allowed_file(self, filename):
  27. return '.' in filename and filename.rsplit('.', 1)[1] in set(['xml'])
  28. @route('/upload', methods=['POST'])
  29. def upload_file(self):
  30. try:
  31. if request.method == 'POST':
  32. file = request.files['file']
  33. if file and self.allowed_file(file.filename):
  34. file.save(os.path.join(self.api.app.config['UPLOAD_FOLDER'], "beer.xml"))
  35. self.api.notify(headline="Upload Successful", message="The Beer XML file was uploaded succesfully")
  36. return ('', 204)
  37. return ('', 404)
  38. except Exception as e:
  39. self.api.notify(headline="Upload Failed", message="Failed to upload Beer xml", type="danger")
  40. return ('', 500)
  41. @route('/<int:id>', methods=['POST'])
  42. def load(self, id):
  43. steps = self.getSteps(id)
  44. boil_time_alerts = self.getBoilAlerts(id)
  45. name = self.getRecipeName(id)
  46. self.api.set_config_parameter("brew_name", name)
  47. boil_time = self.getBoilTime(id)
  48. mashstep_type = cbpi.get_config_parameter("step_mash", "MashStep")
  49. mashinstep_type = cbpi.get_config_parameter("step_mashin", "MashInStep")
  50. mash_kettle = cbpi.get_config_parameter("step_mash_kettle", None)
  51. boilstep_type = cbpi.get_config_parameter("step_boil", "BoilStep")
  52. boil_kettle = cbpi.get_config_parameter("step_boil_kettle", None)
  53. boil_temp = 100 if cbpi.get_config_parameter("unit", "C") == "C" else 212
  54. # READ KBH DATABASE
  55. Step.delete_all()
  56. StepView().reset()
  57. try:
  58. # Add mash in or mash step, depends on timer > 0
  59. for row in steps:
  60. if row.get("timer") > 0:
  61. Step.insert(**{"name": row.get("name"), "type": mashstep_type,
  62. "config": {"kettle": mash_kettle, "temp": float(row.get("temp")),
  63. "timer": row.get("timer")}})
  64. else:
  65. Step.insert(**{"name": row.get("name"), "type": mashinstep_type,
  66. "config": {"kettle": mash_kettle, "temp": float(row.get("temp"))}})
  67. # Add chilling step
  68. Step.insert(**{"name": "ChilStep", "type": "ChilStep", "config": {"timer": 15}})
  69. # Add boiling step
  70. Step.insert(**{
  71. "name": "Boil",
  72. "type": boilstep_type,
  73. "config": {
  74. "kettle": boil_kettle,
  75. "temp": boil_temp,
  76. "timer": boil_time,
  77. # Beer XML defines additions as the total time spent in boiling,
  78. # CBP defines it as time-until-alert
  79. # Also, The model supports five boil-time additions.
  80. # Set the rest to None to signal them being absent
  81. "hop_1": boil_time - boil_time_alerts[0] if len(boil_time_alerts) >= 1 else None,
  82. "hop_2": boil_time - boil_time_alerts[1] if len(boil_time_alerts) >= 2 else None,
  83. "hop_3": boil_time - boil_time_alerts[2] if len(boil_time_alerts) >= 3 else None,
  84. "hop_4": boil_time - boil_time_alerts[3] if len(boil_time_alerts) >= 4 else None,
  85. "hop_5": boil_time - boil_time_alerts[4] if len(boil_time_alerts) >= 5 else None
  86. }
  87. })
  88. # Add Whirlpool step
  89. Step.insert(**{"name": "Whirlpool", "type": "ChilStep", "config": {"timer": 15}})
  90. StepView().reset()
  91. self.api.emit("UPDATE_ALL_STEPS", Step.get_all())
  92. self.api.notify(headline="Recipe %s loaded successfully" % name, message="")
  93. except Exception as e:
  94. self.api.notify(headline="Failed to load Recipe", message=e.message, type="danger")
  95. return ('', 500)
  96. return ('', 204)
  97. def getRecipeName(self, id):
  98. e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
  99. return e.find('./RECIPE[%s]/NAME' % (str(id))).text
  100. def getBoilTime(self, id):
  101. e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
  102. return float(e.find('./RECIPE[%s]/BOIL_TIME' % (str(id))).text)
  103. def getBoilAlerts(self, id):
  104. e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
  105. recipe = e.find('./RECIPE[%s]' % (str(id)))
  106. alerts = []
  107. for e in recipe.findall('./HOPS/HOP'):
  108. use = e.find('USE').text
  109. ## Hops which are not used in the boil step should not cause alerts
  110. if use != 'Aroma' and use != 'Boil':
  111. continue
  112. alerts.append(float(e.find('TIME').text))
  113. ## There might also be miscelaneous additions during boild time
  114. for e in recipe.findall('MISCS/MISC[USE="Boil"]'):
  115. alerts.append(float(e.find('TIME').text))
  116. ## Dedupe and order the additions by their time, to prevent multiple alerts at the same time
  117. alerts = sorted(list(set(alerts)))
  118. ## CBP should have these additions in reverse
  119. alerts.reverse()
  120. return alerts
  121. def getSteps(self, id):
  122. e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
  123. steps = []
  124. for e in e.findall('./RECIPE[%s]/MASH/MASH_STEPS/MASH_STEP' % (str(id))):
  125. if self.api.get_config_parameter("unit", "C") == "C":
  126. temp = float(e.find("STEP_TEMP").text)
  127. else:
  128. temp = round(9.0 / 5.0 * float(e.find("STEP_TEMP").text) + 32, 2)
  129. if e.find("STEP_TIME").text is None:
  130. stepTime = 0.0
  131. else:
  132. stepTime = float(e.find("STEP_TIME").text)
  133. steps.append({"name": e.find("NAME").text, "temp": temp, "timer": stepTime})
  134. return steps
  135. @cbpi.initalizer()
  136. def init(cbpi):
  137. BeerXMLImport.api = cbpi
  138. BeerXMLImport.register(cbpi.app, route_base='/api/beerxml')