Thermomètre - Baromètre :

Cette application logicielle utilise simultanément deux cartes USB de l'ouvrage "L'USB pour tous" : la carte Thermomètre et la carte Baromètre.

C'est une fonctionnalité peu courante : on rencontre généralement un logiciel dédié à un montage USB.

On pourra se plonger dans le code source pour voir comment cela a été réalisé !

Ces deux cartes devront bien sûr être connectées chacune à un port USB libre.

 

Carte_thermo.png     Carte_baro1.png

 

On retrouvera dans l'interface graphique de cette application des composantes du logiciel Baromètre et du logiciel Thermomètre (version 2) :

thermo_barometre.png

Le code source du programme :

  1. #!/usr/bin/python
  2. #-*- coding: iso-8859-15 -*-
  3.  
  4. # Copyright 2014 Vincent LE MIEUX
  5.  
  6. # Contact : vlemieux@laboiteaphysique.fr
  7.  
  8. # La version la plus récente de ce programme se trouve
  9. # sur le site de l'auteur : www.laboiteaphysique.fr
  10.  
  11. # Ce programme est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant
  12. # les termes de la GNU General Public License telle que publiée par la Free Software Foundation ;
  13. # soit la version 3 de la licence, soit (à votre gré) toute version ultérieure.
  14.  
  15. # Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ;
  16. # sans même la garantie tacite de QUALITÉ MARCHANDE ou d'ADÉQUATION à UN BUT PARTICULIER.
  17. # Consultez la GNU General Public License pour plus de détails.
  18.  
  19. # Vous devez avoir reçu une copie de la GNU General Public License en même temps que ce programme ;
  20. # si ce n'est pas le cas, consultez <http://www.gnu.org/licenses>.
  21.  
  22. from gi.repository import Gtk, GObject
  23.  
  24. import os, sys
  25. from time import sleep
  26. import usb.core
  27. import usb.util
  28.  
  29. import xlwt
  30. from xlwt import Workbook
  31.  
  32.  
  33. class THERMOBARO(Gtk.Window):
  34. def __init__(self):
  35.  
  36. self.builder = Gtk.Builder()
  37. self.builder.add_from_file("thermo_baro.glade")
  38.  
  39. #recuperation des widgets utilises par le programme :
  40.  
  41. self.lbA = self.builder.get_object("lbA")
  42. self.lbB = self.builder.get_object("lbB")
  43. self.sb_altitude = self.builder.get_object("sb_altitude")
  44. self.rb_hPa = self.builder.get_object("rb_hPa")
  45. self.rb_mmHg = self.builder.get_object("rb_mmHg")
  46. self.swAcq = self.builder.get_object("swAcq")
  47. self.bt_Quitter = self.builder.get_object("bt_Quitter")
  48. self.bt_Save = self.builder.get_object("bt_Save")
  49. self.bt_Effacer = self.builder.get_object("bt_Effacer")
  50. self.sb_timer = self.builder.get_object("sb_timer")
  51. self.textview = self.builder.get_object("textview")
  52. self.textbuffer = self.builder.get_object("textbuffer")
  53. self.scrolledwindow1 = self.builder.get_object("scrolledwindow1")
  54.  
  55. self.filechooserdialog = self.builder.get_object("filechooserdialog")
  56. self.cb_Filtre = self.builder.get_object("cb_Filtre")
  57.  
  58. self.builder.connect_signals(self)
  59.  
  60. window = self.builder.get_object('window')
  61. window.show_all()
  62.  
  63. #initialisations :
  64.  
  65. self.delai = 1000
  66. self.i = 0
  67. self.texte = ""
  68. self.cb_Filtre.set_active(0)
  69. self.text_unite = '(hPa)'
  70. self.texte = 't(s)' + '\t' + 'T(' + u"°C" +')'+ '\t' + 'P' + self.text_unite + '\r' + '\n'
  71. self.textbuffer.set_text("")
  72.  
  73. #création d'un classeur pour le tableur :
  74. global classeur
  75. classeur = Workbook()
  76. self.feuille1 = classeur.add_sheet("Mesures", cell_overwrite_ok=True)
  77. self.feuille1.write(0,0,'t(s)',xlwt.easyxf("align: horiz center"))
  78. self.feuille1.write(0,1,'T(' + u"°C" +')',xlwt.easyxf("align: horiz center"))
  79. self.feuille1.write(0,2,'P(hPa)',xlwt.easyxf("align: horiz center"))
  80. self.feuille1.write(0,3,'P(mmHg)',xlwt.easyxf("align: horiz center"))
  81.  
  82. thermo = usb.core.find(idVendor=0x0C70, idProduct = 0xF0A3)
  83.  
  84. if thermo is None:
  85. msg = "Carte thermometre non détectée : vérifier qu'elle est bien branchée sur un port USB, et bien alimentée ! Ce programme va se refermer ..."
  86. dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
  87. # Montre le dialog
  88. dialog.run()
  89. # Destruction du dialog
  90. dialog.destroy()
  91.  
  92. config = thermo.get_active_configuration()
  93. interface = config[(0,0)]
  94.  
  95. self.ep_out = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT)
  96. self.ep_in = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)
  97.  
  98.  
  99. baro = usb.core.find(idVendor=0x0C70, idProduct = 0xF0A5)
  100.  
  101. if baro is None:
  102. msg = "Carte baromètre non détectée : vérifier qu'elle est bien branchée sur un port USB, et bien alimentée ! Ce programme va se refermer ..."
  103. dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
  104. # Montre le dialog
  105. dialog.run()
  106. # Destruction du dialog
  107. dialog.destroy()
  108.  
  109. config_baro = baro.get_active_configuration()
  110. interface_baro = config_baro[(0,0)]
  111.  
  112. self.ep_out_baro = usb.util.find_descriptor(interface_baro, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT)
  113. self.ep_in_baro = usb.util.find_descriptor(interface_baro, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)
  114.  
  115. self.pour_rien()
  116. self.affiche()
  117. self.timer_afficheur = GObject.timeout_add(1000, self.affiche)
  118.  
  119. def pour_rien(self):
  120. self.ep_out.write('M')
  121. self.ep_out_baro.write('M')
  122. sleep(0.02)
  123. pour_rien = self.ep_in.read(1)
  124. pour_rien = self.ep_in_baro.read(2)
  125. sleep(0.02)
  126.  
  127.  
  128. def affiche(self):
  129. self.ep_out.write('M')
  130. temp_affiche = self.ep_in.read(1)
  131. self.lbA.set_text(str("{:.1f}".format ( temp_affiche[0]*0.5)) + u" °C")
  132.  
  133. self.ep_out_baro.write('M')
  134. pression = self.ep_in_baro.read(2)
  135. pression_hPa = (pression[1]*256 + pression[0])*0.5 + self.sb_altitude.get_value()/8.3
  136. pression_mmHg = pression_hPa*760/1013.24
  137. if self.rb_hPa.get_active():
  138. self.lbB.set_text(str("{:.0f}".format ( pression_hPa)))
  139. #self.lb_unite.set_text("hPa")
  140. if self.rb_mmHg.get_active():
  141. self.lbB.set_text(str("{:.0f}".format ( pression_mmHg)))
  142. #self.lb_unite.set_text("mmHg")
  143. return True
  144.  
  145. def mesure(self):
  146. self.pour_rien()
  147. if self.i < 65536 :
  148.  
  149. self.ep_out.write('M')
  150. temperature = self.ep_in.read(1)
  151. self.ep_out_baro.write('M')
  152.  
  153. pression = self.ep_in_baro.read(2)
  154. pression_hPa = (pression[1]*256 + pression[0])*0.5 + self.sb_altitude.get_value()/8.3
  155. pression_mmHg = pression_hPa*760/1013.24
  156. if self.rb_hPa.get_active():
  157. text_pression = str("{:.0f}".format ( pression_hPa))
  158.  
  159. if self.rb_mmHg.get_active():
  160. text_pression = str("{:.0f}".format ( pression_mmHg))
  161.  
  162. self.texte +=(str(self.i*self.delai/1000) + '\t' + str("{:.1f}".format (temperature[0]*0.5)).replace('.', ',') + '\t' + text_pression + '\r' + '\n' )
  163. self.textbuffer.set_text(self.texte)
  164. adjustment = self.scrolledwindow1.get_vadjustment()
  165. adjustment.set_value(adjustment.get_upper())
  166.  
  167. self.feuille1.write(self.i+1,0,self.i*self.delai/1000,xlwt.easyxf("align: horiz center"))
  168. self.feuille1.write(self.i+1,1,float(str("{:.1f}".format (temperature[0]*0.5))),xlwt.easyxf("align: horiz center"))
  169. self.feuille1.write(self.i+1,2,float(str("{:.0f}".format ( pression_hPa))),xlwt.easyxf("align: horiz center"))
  170. self.feuille1.write(self.i+1,3,float(str("{:.0f}".format ( pression_mmHg))),xlwt.easyxf("align: horiz center"))
  171. self.i = self.i + 1
  172. return True
  173.  
  174. def on_sb_timer_value_changed(self,widget):
  175. self.delai = int(1000*self.sb_timer.get_value())
  176.  
  177. def on_swAcq_button_press_event(self,widget,event):
  178. if widget.get_active()==False :
  179. self.pour_rien()
  180. self.effacer()
  181. self.mesure()
  182. self.timer_id = GObject.timeout_add(self.delai, self.mesure)
  183. self.sb_altitude.set_sensitive(False)
  184. self.rb_hPa.set_sensitive(False)
  185. self.rb_mmHg.set_sensitive(False)
  186. self.bt_Quitter.set_sensitive(False)
  187. self.bt_Effacer.set_sensitive(False)
  188. self.bt_Save.set_sensitive(False)
  189. self.sb_timer.set_sensitive(False)
  190.  
  191. else:
  192. GObject.source_remove(self.timer_id)
  193. self.sb_altitude.set_sensitive(True)
  194. self.rb_hPa.set_sensitive(True)
  195. self.rb_mmHg.set_sensitive(True)
  196. self.bt_Quitter.set_sensitive(True)
  197. self.bt_Effacer.set_sensitive(True)
  198. self.bt_Save.set_sensitive(True)
  199. self.sb_timer.set_sensitive(True)
  200.  
  201. def effacer(self):
  202. self.texte = ' '
  203. if self.rb_hPa.get_active():
  204. self.text_unite = '(hPa)'
  205. if self.rb_mmHg.get_active():
  206. self.text_unite = '(mmHg)'
  207. self.texte = 't(s)' + '\t' + 'T(' + u"°C" +')' + '\t' + 'P' + self.text_unite + '\r' + '\n'
  208. self.textbuffer.set_text(self.texte)
  209. for j in range (self.i) :
  210. self.feuille1.write(j+1,0,'')
  211. self.feuille1.write(j+1,1,'')
  212. self.feuille1.write(j+1,2,'')
  213. self.feuille1.write(j+1,3,'')
  214. self.i = 0
  215.  
  216. def on_bt_Effacer_clicked(self,widget) :
  217. self.effacer()
  218.  
  219. def on_bt_Save_clicked(self,widget):
  220.  
  221. reponse = self.filechooserdialog.run()
  222. if reponse == 1:
  223. # Enregistrement format Calc :
  224. if self.cb_Filtre.get_active() ==0 :
  225. nom = self.filechooserdialog.get_filename()
  226. if not nom.endswith('.ods'):
  227. fichier_ods = nom + '.ods'
  228. else :
  229. fichier_ods = nom
  230. with open(fichier_ods, 'w') :
  231. classeur.save(fichier_ods)
  232.  
  233. # Enregistrement au format Gnumeric :
  234. if self.cb_Filtre.get_active() == 1 :
  235. nom = self.filechooserdialog.get_filename()
  236. if not nom.endswith('.gnumeric'):
  237. fichier_gnum = nom + '.gnumeric'
  238. else :
  239. fichier_gnum = nom
  240. with open(fichier_gnum, 'w') :
  241. classeur.save(fichier_gnum)
  242. self.filechooserdialog.hide()
  243.  
  244. def on_bt_Quitter_clicked(self,widget):
  245. Gtk.main_quit()
  246.  
  247. def on_window_destroy(self,widget):
  248. GObject.source_remove(self.timer_id)
  249. GObject.source_remove(self.timer_afficheur)
  250. Gtk.main_quit()
  251.  
  252. def destroy(window, self):
  253. GObject.source_remove(self.timer_id)
  254. GObject.source_remove(self.timer_afficheur)
  255. Gtk.main_quit()
  256.  
  257. def main():
  258. app = THERMOBARO()
  259. Gtk.main()
  260.  
  261.  
  262.  
  263. if __name__ == "__main__":
  264.  
  265. sys.exit(main())
  266.  

This site uses cookies. Some of the cookies we use are essential for parts of the site to operate and have already been set. You may delete and block all cookies from this site, but parts of the site will not work.