S&B Volcano vaporizer remote control with Pi Pico W
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.

ota.py 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #!/usr/bin/env python3
  2. # Uses the Gitea API to fetch the latest revision of the project from a repo.
  3. #
  4. # Inspired by:
  5. # https://github.com/olivergregorius/micropython_ota
  6. #
  7. # ----------------------------------------------------------------------------
  8. # Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  9. #
  10. # This program is free software: you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation, either version 3 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # See <http://www.gnu.org/licenses/>.
  21. # ----------------------------------------------------------------------------
  22. import util
  23. import sys
  24. import os
  25. class StateUpdate:
  26. def __init__(self, lcd):
  27. self.host = "https://git.xythobuz.de"
  28. self.repo = "thomas/sb-py"
  29. self.branch = None
  30. self.exe_path = "states.py"
  31. self.blacklist = [
  32. "README.md",
  33. "COPYING",
  34. ".gitignore",
  35. "python-test/.gitignore",
  36. "python-test/copy.sh",
  37. "web-app/fetch.sh",
  38. ]
  39. self.lcd = lcd
  40. self.get = None
  41. self.version_file = "_ota_version"
  42. def fetch(self, url):
  43. # lazily initialize WiFi
  44. if self.get == None:
  45. self.get, post = util.getRequests()
  46. if self.get == None:
  47. return None
  48. try:
  49. #print("GET " + url)
  50. r = self.get(url)
  51. # explitic close on Response object not needed,
  52. # handled internally by r.content / r.text / r.json()
  53. # to avoid this automatic behaviour, first access r.content
  54. # to trigger caching it in response object, then close
  55. # socket.
  56. tmp = r.content
  57. if hasattr(r, "raw"):
  58. if r.raw != None:
  59. r.raw.close()
  60. r.raw = None
  61. return r
  62. except Exception as e:
  63. print()
  64. print(url)
  65. if hasattr(sys, "print_exception"):
  66. sys.print_exception(e)
  67. else:
  68. print(e)
  69. print()
  70. return None
  71. def get_stored_commit(self):
  72. current = "unknown"
  73. try:
  74. f = open(self.version_file, "r")
  75. current = f.readline().strip()
  76. f.close()
  77. except Exception as e:
  78. print()
  79. if hasattr(sys, "print_exception"):
  80. sys.print_exception(e)
  81. else:
  82. print(e)
  83. print()
  84. return current
  85. def get_previous_commit(self, commit):
  86. r = self.fetch(self.host + "/" + self.repo + "/commit/" + commit).text
  87. for line in r.splitlines():
  88. if not (self.repo + "/commit/") in line:
  89. continue
  90. line = line[line.find("/commit/") : ][8 : ][ : 40]
  91. if line != commit:
  92. return line
  93. return "unknown"
  94. def check(self, verbose = False):
  95. if self.branch == None:
  96. # get default branch
  97. r = self.fetch(self.host + "/api/v1/repos/" + self.repo).json()
  98. self.branch = r["default_branch"]
  99. if verbose:
  100. print("Selected default branch " + self.branch)
  101. # check for latest commit in branch
  102. r = self.fetch(self.host + "/api/v1/repos/" + self.repo + "/branches/" + self.branch).json()
  103. commit = r["commit"]["id"]
  104. if verbose:
  105. print("Latest commit is " + commit)
  106. current = self.get_stored_commit()
  107. if verbose:
  108. if current != commit:
  109. print("Current commit " + current + " is different!")
  110. else:
  111. print("No update required")
  112. return (current != commit, commit)
  113. def update_to_commit(self, commit, verbose = False):
  114. # list all files for a commit
  115. r = self.fetch(self.host + "/api/v1/repos/" + self.repo + "/git/trees/" + commit).json()
  116. # TODO does not support sub-folders
  117. if verbose:
  118. if len(r["tree"]) > 0:
  119. print(str(len(r["tree"])) + " files in repo:")
  120. for f in r["tree"]:
  121. if f["path"] in self.blacklist:
  122. print(" - (IGNORED) " + f["path"])
  123. else:
  124. print(" - " + f["path"])
  125. else:
  126. print("No files in repo?!")
  127. for f in r["tree"]:
  128. if f["path"] in self.blacklist:
  129. continue
  130. # get a file from a commit
  131. r = self.fetch(self.host + "/" + self.repo + "/raw/commit/" + commit + "/" + f["path"]).text
  132. if verbose:
  133. print("Writing " + f["path"])
  134. # overwrite existing file
  135. fo = open(f["path"], "w")
  136. fo.write(r)
  137. fo.close()
  138. if f["path"] == self.exe_path:
  139. if verbose:
  140. print("Writing " + f["path"] + " to main.py")
  141. fo = open("./main.py", "w")
  142. fo.write(r)
  143. fo.close()
  144. # Write new commit id to local file
  145. f = open(self.version_file, "w")
  146. f.write(commit + "\n")
  147. f.close()
  148. def pico_ota_run():
  149. print("Checking for updates")
  150. newer, commit = ota.check(True)
  151. if newer:
  152. print("Updating to:", commit)
  153. ota.update_to_commit(commit, True)
  154. print("Resetting")
  155. machine.soft_reset()