Bonjour,

Je souhaite expérimenter le projet suivant : https://riton-duino.blogspot.com/202...l-version.html
le but étant de pouvoir visualiser sur PC des données temps réel (datalogger)
Pour ce faire l'auteur utilise CHERRYPY

J'ai commencé par installer Python 3.13 puis CherryPy (CherryPy.dev )
pour serveur CherryPy , j'ai utilisé l'exemple : py -m cherrypy.tutorial.tut01_helloworld
et la réponse est positive

Fort de tout cela , j'ai lancé le fichier via 192.168.x.x/index.html pour définir les entrées de l'ESP32 à surveiller , dans mon cas j'ai simplement mis 5v sur l'entrée ADC36 au travers de 2 résistances de 10k
puis j'ai lancé le fichier index.py sous l'invite de commande via cherrypy mais il ne trouve pas le fichier Host permettant de tracer le graphique
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
C:\Users\Utilisateur\AppData\Local\Programs\Python\Python313\Lib\site-packages\cherrypy>py -m cherrypy.essai.index
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\Utilisateur\AppData\Local\Programs\Python\Python313\Lib\site-packages\cherrypy\essai\index.py", line 8, in <module>
    from cherrypy.lib.cptools import serve_file;
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ImportError: cannot import name 'serve_file' from 'cherrypy.lib.cptools' (C:\Users\Utilisateur\AppData\Local\Programs\Python\Python313\Lib\site-packages\cherrypy\lib\cptools.py)
je joins ici les fichiers index.py et template.py pour une meilleure compréhension car pour ma part je découvre python et je ne suis pas encore familiarisé avec ce type de language

index.py
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 
#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sys, os, locale, logging
from datetime import datetime
from dateutil import parser
import cherrypy
from cherrypy.lib.cptools import serve_file; 
from template import Template
 
logger = logging.getLogger('index')
 
current_dir = os.path.realpath(os.path.curdir)
 
gpioSerie = """
        {
          name: '%s',
          type: 'spline',
          data: [%s],
        },
		"""
 
adcSerie = """
        {
          name: '%s',
          type: 'spline',
          data: [%s],
          tooltip: {
              valueSuffix: 'V'
          },
        },
		"""
 
class HomePage(object):
 
	def __init__(self):
		logger.setLevel(logging.DEBUG)
		ch = logging.StreamHandler()
		ch.setLevel(logging.DEBUG)
		formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
		ch.setFormatter(formatter)
		logger.addHandler(ch)
		self.data = {}
		self.xLabel = 's'
 
	def load(self, fileName):
		f = open(fileName, 'r')
		return f.read()
 
	def getXData(self):
		data = ''
		k = self.data.keys()
		k.sort()
		for dt in k:
			if len(data) > 0:
				data += ', '
			data += "Date.UTC(%s, %s, %s, %s, %s, %s, %s)" % (dt.year, dt.month-1, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond/1000)
 
		return data
 
	def hasPowerData(self):
		k = self.data.keys()
		k.sort()
		if len(k) and 'CURRENT' in self.data[k[0]]:
			return True
		return False
 
	def hasGpioData(self):
		k = self.data.keys()
		k.sort()
		if len(k):
			gpioList = self.data[k[0]]
			for gpio in gpioList:
				serie = ''
				if gpio.startswith('GPIO'):
					return True
		return False
 
	def hasAdcData(self):
		k = self.data.keys()
		k.sort()
		if len(k):
			adcList = self.data[k[0]]
			for adc in adcList:
				serie = ''
				if adc.startswith('ADC'):
					return True
		return False
 
	def getCurrentData(self):
		data = ''
		k = self.data.keys()
		k.sort()
		if len(k) and 'CURRENT' in self.data[k[0]]:
			for entry in k:
				if len(data) > 0:
					data += ', '
				data += self.data[entry]['CURRENT']
		return data
 
	def getVoltageData(self):
		data = ''
		k = self.data.keys()
		k.sort()
		if len(k) and 'VOLTAGE' in self.data[k[0]]:
			for entry in k:
				if len(data) > 0:
					data += ', '
				data += self.data[entry]['VOLTAGE']
		return data
 
	def getGpioSeries(self):
		data = ''
		k = self.data.keys()
		k.sort()
		if len(k):
			gpioList = self.data[k[0]]
			for gpio in gpioList:
				serie = ''
				if gpio.startswith('GPIO'):
					id = gpio
					if not gpio[4:].isdigit():
						id = gpio[5:]
					for entry in k:
						if len(serie) > 0:
							serie += ', '
						serie += self.data[entry][gpio]
					data += gpioSerie % (id, serie)
		return data
 
	def getAdcSeries(self):
		data = ''
		k = self.data.keys()
		k.sort()
		if len(k):
			adcList = self.data[k[0]]
			for adc in adcList:
				serie = ''
				if adc.startswith('ADC'):
					id = adc
					if not adc[3:].isdigit():
						id = adc[4:]
					for entry in k:
						if len(serie) > 0:
							serie += ', '
						serie += self.data[entry][adc]
					data += adcSerie % (id, serie)
		return data
 
	@cherrypy.expose
	def favicon_ico(self):
		current_dir = os.path.realpath(os.path.curdir)
		return serve_file(current_dir + '/favicon.ico')
 
	@cherrypy.expose
	def index(self):
		tmpl = self.load('index.html')
		nameSpace = {'XDATA': self.getXData(),
					   	'XLABEL': self.xLabel,
					   	'CURRENT_DATA': self.getCurrentData(),
						'VOLTAGE_DATA': self.getVoltageData(),
						'GPIO_SERIES': self.getGpioSeries(),
						'ADC_SERIES': self.getAdcSeries(),
						'DISPLAY_POWER': "block" if self.hasPowerData() else "none",
						'DISPLAY_GPIO': "block" if self.hasGpioData() else "none",
						'DISPLAY_ADC': "block" if self.hasAdcData() else "none"
					}
		return Template(tmpl, searchList=[nameSpace]).respond()
 
	@cherrypy.expose
	def clear(self):
		self.data = {}
		raise cherrypy.HTTPRedirect("/") 
 
	@cherrypy.expose
	def export(self, filename='log.csv'):
		k = self.data.keys()
		k.sort()
		data = 'TIME'
		if len(k):
			f = open(filename, 'w')
			columns = self.data[k[0]].keys()
			columns.sort()
			for col in columns:
				data += ';'
				data += col
			data += '\n'
			f.write(data)
			data = ''
			for entry in k:
				data += str(entry)
				for col in columns:
					data += ';'
					data += self.data[entry][col]
				data += '\n'
				f.write(data)
				data = ''
			f.close()
			path = os.path.join(os.getcwd(), filename)
			return serve_file(path, 'application/x-download', 'attachment', os.path.basename(path))
 
	@cherrypy.expose
	def log(self, **kwargs):
		logger.debug('log %s' % kwargs)
		if "dt" in kwargs:
			dt = parser.parse(kwargs["dt"])
		else:
			dt = datetime.now()
		self.data[dt] = {}
		for arg in kwargs.keys():
			self.data[dt][arg] = kwargs[arg]
		tmpl = self.load('index.html')
		return "OK"
 
cherrypy.root = HomePage()
 
if __name__ == '__main__':
	cherrypy.config.update(file = 'web-power-monitor.conf')
	cherrypy.log('SERVER starting at %s' % os.getcwd())
	cherrypy.server.start()
template.py

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
import logging
 
logger = logging.getLogger("index")
 
class Template(object):
 
	def __init__(self, template, nameSpace=None, searchList=None):
		self.template = template
		self.nameSpace = nameSpace
		self.searchList = searchList
 
	def search(self, name):
		if self.searchList:
			for nameSpace in self.searchList:
				if name in nameSpace:
					return nameSpace[name]
		if self.nameSpace:
			for nameSpace in self.nameSpace:
				if name in nameSpace:
					return nameSpace[name]
		return None
 
	def respond(self):
		text = ''
		found = False
		escape = False
		for i in range(len(self.template)):
			c = self.template[i]
			if found:
				if c.isalnum() or c in '-_':
					name += c
				else:
					if len(name):
						value = self.search(name)
						if value <> None:
							text += str(value)
						else:
							text += '$' + name
					else:
						text += '$'
					text += c
					found = False
			elif c == '\\':
				escape = True
			elif c == '$':
				if escape :
					text += c
					escape = False
				else:
					name = ''
					found = True
			else:
				if escape :
					text += '\\'
					escape = False
				text += c
		return text
Ces deux fichiers font appel au serveur avec la commande 127.0.0.1:8080 pour afficher le graphique malheureusement , il semblerait qu'ils ne trouvent pas le fichier Host et j'en ne connait la raison

Ma question est donc la suivante : quelqu'un connaitrait-il CHERRYPY et la patience de m'expliquer le principe de fonctionnement avec un ESP32 ou connaitrait-il un autre moyen facile de visualiser des graphiques temps réel sur PC

Mille mercis de m'avoir lu
Pascal