Compare commits
	
		
			3 Commits
		
	
	
		
			5f84dad372
			...
			integratio
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2e59700bfa | |||
| 88aced27bf | |||
| 25610fd4fa | 
							
								
								
									
										
											BIN
										
									
								
								api_server/__pycache__/__init__.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								api_server/__pycache__/app.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								api_server/__pycache__/state.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										233
									
								
								api_server/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,233 @@ | ||||
| """ | ||||
| Lancer avec python -m flask --debug --app server\\__init__.py run | ||||
| """ | ||||
| import logging | ||||
| import sys | ||||
| import time | ||||
|  | ||||
| from flask import Flask, request, session | ||||
| import multiprocessing as mp | ||||
| from api_worker.__init__ import run_instance | ||||
| import uuid | ||||
| from flask_cors import CORS | ||||
|  | ||||
| app = Flask("COCOSIM") | ||||
| CORS(app, supports_credentials=True) | ||||
| app.secret_key = bytes.fromhex('192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf') | ||||
|  | ||||
|  | ||||
| class ProcessBase(object): | ||||
|     SESSION_MAX_AGE = 60 * 5 | ||||
|  | ||||
|     def __init__(self): | ||||
|         self._cmd_q = {} | ||||
|         self._state_q = {} | ||||
|         self._process = {} | ||||
|         self._last = {} | ||||
|  | ||||
|     def known(self): | ||||
|         return 'id' in session and session['id'] in self._cmd_q | ||||
|  | ||||
|     def update(self): | ||||
|         self._last[session['id']] = time.time() | ||||
|  | ||||
|     def cmd_q(self): | ||||
|         self.update() | ||||
|         return self._cmd_q[session['id']] | ||||
|  | ||||
|     def state_q(self): | ||||
|         self.update() | ||||
|         return self._state_q[session['id']] | ||||
|  | ||||
|     def init_q(self): | ||||
|         self.update() | ||||
|         self._state_q[session['id']] = mp.Queue() | ||||
|         self._cmd_q[session['id']] = mp.Queue() | ||||
|  | ||||
|     def init_process(self, p): | ||||
|         self.update() | ||||
|         self.cleanup() | ||||
|         self._process[session['id']] = p | ||||
|  | ||||
|     def process(self): | ||||
|         return self._process[session['id']] | ||||
|  | ||||
|     def purge(self, k=None): | ||||
|         if k is None: | ||||
|             k = session['id'] | ||||
|  | ||||
|         del self._cmd_q[k] | ||||
|         del self._state_q[k] | ||||
|         del self._process[k] | ||||
|         del self._last[k] | ||||
|  | ||||
|     def quit(self): | ||||
|         self.purge() | ||||
|         self.cleanup() | ||||
|  | ||||
|     def cleanup(self): | ||||
|         ctime = time.time() | ||||
|         to_purge = [] | ||||
|  | ||||
|         for k, v in self._last.items(): | ||||
|             if ctime - v > self.SESSION_MAX_AGE: | ||||
|                 to_purge.append(k) | ||||
|  | ||||
|         for k in to_purge: | ||||
|             logging.info(f"Purging {k}") | ||||
|             self.purge(k) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return str(list(self._process.keys())) | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self._process.keys()) | ||||
|  | ||||
|  | ||||
| PROCESS_BASE = ProcessBase() | ||||
|  | ||||
|  | ||||
| @app.route('/') | ||||
| def hello(): | ||||
|     PROCESS_BASE.cleanup() | ||||
|     return f"Hello sailor !\nProcess base : {str(PROCESS_BASE)}" | ||||
|  | ||||
|  | ||||
| @app.route('/init') | ||||
| def init(): | ||||
|     session['id'] = uuid.uuid4().int | ||||
|     PROCESS_BASE.init_q() | ||||
|     PROCESS_BASE.init_process(mp.Process(target=run_instance, args=(session['id'], PROCESS_BASE.cmd_q(), PROCESS_BASE.state_q()))) | ||||
|     PROCESS_BASE.process().start() | ||||
|     return "OK" | ||||
|  | ||||
|  | ||||
| @app.route('/start') | ||||
| def start(): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "start"}) | ||||
|     return "OK" | ||||
|  | ||||
|  | ||||
| @app.route('/stop') | ||||
| def stop(): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "stop"}) | ||||
|     return "OK" | ||||
|  | ||||
|  | ||||
| @app.route('/state') | ||||
| def state(): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "state"}) | ||||
|     data = PROCESS_BASE.state_q().get() | ||||
|     return data | ||||
|  | ||||
|  | ||||
| @app.route('/quit') | ||||
| def quit(): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         PROCESS_BASE.cleanup() | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "quit"}) | ||||
|     PROCESS_BASE.process().join() | ||||
|     PROCESS_BASE.quit() | ||||
|     del session['id'] | ||||
|     logging.info("Purge effectuée") | ||||
|     return "OK" | ||||
|  | ||||
|  | ||||
| @app.route('/load', methods=['POST']) | ||||
| def load(): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     try: | ||||
|         data = request.json | ||||
|         PROCESS_BASE.cmd_q().put({'cmd': "load", "args": data}) | ||||
|     except Exception: | ||||
|         logging.exception("ERROR") | ||||
|         return "Error", 418 | ||||
|  | ||||
|     if PROCESS_BASE.state_q().get() == "OK": | ||||
|         return "OK" | ||||
|     else: | ||||
|         return "Error in graph", 418 | ||||
|  | ||||
|  | ||||
| @app.route('/push/<obj>') | ||||
| def push(obj): | ||||
|     """ | ||||
|     Push button | ||||
|     """ | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "push", "args": obj}) | ||||
|     return "OK" | ||||
|  | ||||
|  | ||||
| @app.route('/release/<obj>') | ||||
| def release(obj): | ||||
|     """ | ||||
|     Release button | ||||
|     """ | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q().put({'cmd': "release", "args": obj}) | ||||
|     return "OK" | ||||
|  | ||||
| @app.route('/pause/<obj>') | ||||
| def pause_simulation(obj): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q.put({'cmd': "pause", "arg": obj}) | ||||
|     return "Simulation paused" | ||||
|  | ||||
| @app.route('/resume/<obj>') | ||||
| def resume_simulation(obj): | ||||
|     if not PROCESS_BASE.known(): | ||||
|         return "Unknown", 401 | ||||
|  | ||||
|     PROCESS_BASE.cmd_q.put({'cmd': "resume", "arg": obj}) | ||||
|     return "Simulation resumed" | ||||
|  | ||||
| def just_run(): | ||||
|     """ | ||||
|     Pour lancer avec gunicorn | ||||
|     """ | ||||
|     mp.set_start_method('spawn') | ||||
|     app.run()  # Ne pas mettre debug en mode multiprocess | ||||
|  | ||||
|  | ||||
| def main(argv): | ||||
|     host = '127.0.0.1' | ||||
|     ssl_context = None | ||||
|     for arg in argv[1:]: | ||||
|         if arg == '-remote': | ||||
|             host = '0.0.0.0' | ||||
|         elif arg == '-secure-cookie': | ||||
|             app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE="True") | ||||
|         elif arg == '-ssl': | ||||
|             ssl_context = 'adhoc' | ||||
|         elif arg == '-h': | ||||
|             print(""" | ||||
| Options :  | ||||
|     -remote : bind on 0.0.0.0 instead of 127.0.0.1 | ||||
|     -secure-cookie : send secure cookie (for browser UI to be happy) | ||||
|     -ssl : enable https with adhoc certificate | ||||
| """) | ||||
|             sys.exit(0) | ||||
|         else: | ||||
|             print(f"Unknown argument : {arg}") | ||||
|             sys.exit(-1) | ||||
|     mp.set_start_method('spawn') | ||||
|     app.run(debug=False, host=host, port=5555, ssl_context=ssl_context)  # Ne pas mettre debug en mode multiprocess | ||||
							
								
								
									
										46
									
								
								api_server/state.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,46 @@ | ||||
| import json | ||||
|  | ||||
|  | ||||
| class State(object): | ||||
|     IGNORE = frozenset(['Coude', 'Noeud', 'P24', 'P0', 'Pulse']) | ||||
|     # these components do not have any states (value/ true or flase...) | ||||
|  | ||||
|     Breakpoints = ['Relais'] | ||||
|     #possibility to add other breakpoints in the future ;)  | ||||
|   | ||||
|     def __init__(self, cocosim_server): | ||||
|         self.cocosim_server = cocosim_server | ||||
|         self.conf = self.cocosim_server.conf["ui"] | ||||
|         self.composants = {} | ||||
|         self._exception = None | ||||
|  | ||||
|     def load_conf(self, schema_d): | ||||
|         # Chargement des blocs | ||||
|         for nom, valeur in schema_d['blocs'].items(): | ||||
|             if valeur['type'] not in self.IGNORE: | ||||
|                 self.composants[nom] = None | ||||
|  | ||||
|     def to_json(self): | ||||
|         if self._exception: | ||||
|             return json.dumps({'exn': self._exception}) | ||||
|         else: | ||||
|             return json.dumps(self.composants) | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return self.conf.__iter__ | ||||
|  | ||||
|     def items(self): | ||||
|         return self.composants.items() | ||||
|  | ||||
|     def keys(self): | ||||
|         return self.composants.keys() | ||||
|  | ||||
|     def update(self, nom, valeur): | ||||
|         self.composants[nom] = valeur | ||||
|  | ||||
|     def exception(self, e): | ||||
|         self._exception = e | ||||
|  | ||||
|     def reset_exception(self): | ||||
|         self._exception = None | ||||
|  | ||||
							
								
								
									
										19
									
								
								api_server/test_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| import asyncio | ||||
|  | ||||
|  | ||||
| async def tcp_client(): | ||||
|     reader, writer = await asyncio.open_connection( | ||||
|         '127.0.0.1', 8888) | ||||
|  | ||||
|     while not writer.is_closing(): | ||||
|         message = input("> ") | ||||
|         print(f'Send: {message!r}') | ||||
|         writer.write(message.encode()) | ||||
|         await writer.drain() | ||||
|         if message == "state": | ||||
|             data = await reader.read(1000) | ||||
|         else: | ||||
|             data = await reader.read(100) | ||||
|         print(f'Received: {data.decode()!r}') | ||||
|  | ||||
| asyncio.run(tcp_client()) | ||||
							
								
								
									
										156
									
								
								api_worker/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,156 @@ | ||||
| import json | ||||
| import asyncio | ||||
| from modele.donnees import SchemaReader, GraphStructException | ||||
| from modele.graphe import Graphe | ||||
| from modele.cocosim import Cocosim | ||||
| from api_server.state import State | ||||
| import logging | ||||
| import modele.exceptions | ||||
|  | ||||
| class CocosimInstance(object): | ||||
|     def __init__(self, cmd_q, state_q): | ||||
|         self.runner = None | ||||
|         try: | ||||
|             conf_fp = open("modele/config.json") | ||||
|             conf = json.load(conf_fp) | ||||
|  | ||||
|             self.pause_simulation = False  #pause flag | ||||
|             self.conf = conf | ||||
|             self.dt = self.conf['circuit']['DT'] | ||||
|             self.cocosim = None | ||||
|             self.state = None | ||||
|             self.cmd_q = cmd_q | ||||
|             self.state_q = state_q | ||||
|             self.quit = False | ||||
|         except (OSError, json.JSONDecodeError) as e: | ||||
|             logging.exception("Reading conf. file") | ||||
|             raise modele.G | ||||
|  | ||||
|     def setup(self, schema_d): | ||||
|         logging.info("Setting up") | ||||
|         reader = SchemaReader(schema_d) | ||||
|         reader.process() | ||||
|         logging.info("Schema is loaded") | ||||
|         self.state = State(self) | ||||
|         self.state.load_conf(schema_d) | ||||
|         logging.info(f"State is made up with {len(self.state.composants)} items.") | ||||
|         graphe = Graphe(self.conf['circuit']) | ||||
|         graphe.load_data_from_schema_reader(reader) | ||||
|         logging.info("Graph is initialized.") | ||||
|         self.cocosim = Cocosim(self.conf, graphe, {}, {}) | ||||
|         logging.info("Cocosim is initialized") | ||||
|  | ||||
|     async def handler(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         data = await loop.run_in_executor(None, self.cmd_q.get) | ||||
|         message = data['cmd'] | ||||
|         try: | ||||
|             if message == "start": | ||||
|                 logging.log(logging.INFO, "Starting") | ||||
|                 self.runner = asyncio.create_task(self.run()) | ||||
|                  | ||||
|             elif message == "stop": | ||||
|                 logging.log(logging.INFO, "Stopping") | ||||
|                 await self.stop() | ||||
|  | ||||
|             elif message == "state": | ||||
|                 self.state_q.put(self.state.to_json()) | ||||
|  | ||||
|             elif message == "quit": | ||||
|                 logging.log(logging.INFO, "Quitting") | ||||
|                 await self.stop() | ||||
|                 self.quit = True | ||||
|  | ||||
|             elif message == "load": | ||||
|                 logging.log(logging.INFO, "Loading file") | ||||
|                 try: | ||||
|                     self.setup(data['args'] if type(data['args']) == dict else json.loads(data['args']))  # Compatibilité avec certaines IHM | ||||
|                     self.state_q.put("OK") | ||||
|                 except GraphStructException: | ||||
|                     self.state_q.put("Error") | ||||
|  | ||||
|             elif message == "pause": | ||||
|                 but_name = data['args'] | ||||
|                 logging.log(logging.INFO,"Simulation paused {but_name}") | ||||
|                 self.pause_simulation = True | ||||
|  | ||||
|             elif message == "resume": | ||||
|                 but_name = data['args'] | ||||
|                 logging.log(logging.INFO,"Simulation resumed {but_name}") | ||||
|                 self.pause_simulation = False | ||||
|  | ||||
|             elif message == "push": | ||||
|                 but_name = data['args'] | ||||
|                 logging.log(logging.INFO, f"Push button {but_name}") | ||||
|                 if self.cocosim.graphe[but_name] == "Bouton": | ||||
|                     self.cocosim.graphe[but_name].ferme() | ||||
|                 else: | ||||
|                     self.cocosim.graphe[but_name].bascule() | ||||
|             elif message == "release": | ||||
|                 but_name = data['args'] | ||||
|                 logging.log(logging.INFO, f"Release button {but_name}") | ||||
|                 if self.cocosim.graphe[but_name].type == "Bouton": | ||||
|                     self.cocosim.graphe[but_name].ouvre() | ||||
|                 # Dans le cas contraire on ne traite pas le release | ||||
|             else: | ||||
|                 logging.log(logging.ERROR, "Commande inconnue") | ||||
|         except Exception: | ||||
|             logging.exception("Exception occured in handler") | ||||
|  | ||||
|     def cycle(self): | ||||
|         try: | ||||
|             self.cocosim.cycle() | ||||
|  | ||||
|             for nom in self.state.keys(): | ||||
|                 if nom not in self.cocosim.graphe and nom[-7:] == ".double":  # TODO : a supprimer apràs refactoring contact double | ||||
|                     nom_translate = nom[:-7] + ".travail" | ||||
|                     value = self.cocosim.graphe[nom_translate].etat() if nom_translate in self.cocosim.graphe else None | ||||
|                     self.state.update(nom, value) | ||||
|                 else: | ||||
|                     value = self.cocosim.graphe[nom].etat() if nom in self.cocosim.graphe else None | ||||
|                     self.state.update(nom, value) | ||||
|         except modele.base.SurintensiteException as e: | ||||
|             self.state.exception("Surintensité") | ||||
|             raise e | ||||
|         except modele.base.SurtensionException as e: | ||||
|             self.state.exception("Surtension") | ||||
|             raise e | ||||
|  | ||||
|  | ||||
|     async def run(self): | ||||
|         try: | ||||
|             while not self.quit: | ||||
|                 if not self.pause_simulation: | ||||
|                     self.state.reset_exception() | ||||
|                     self.cycle() | ||||
|                 else:  | ||||
|                     print("Simulation paused. Awaiting resume...") | ||||
|                     while self.pause_simulation: | ||||
|                         await asyncio.sleep(1)  #wait until the simulation is resumed | ||||
|                 await asyncio.sleep(self.dt) | ||||
|         except Exception as e: | ||||
|             logging.exception("Exception occured during simulation run") | ||||
|  | ||||
|     async def stop(self): | ||||
|         if self.runner: | ||||
|             self.runner.cancel() | ||||
|             try: | ||||
|                 await self.runner | ||||
|             except asyncio.CancelledError: | ||||
|                 logging.info("Runner is stopped.") | ||||
|                 self.runner = None | ||||
|  | ||||
|     async def handle_requests(self): | ||||
|         while not self.quit: | ||||
|             await self.handler() | ||||
|         logging.info("Stop handling request") | ||||
|  | ||||
|     def __del__(self): | ||||
|         logging.info("Cocosim instance destroyed") | ||||
|  | ||||
|  | ||||
| def run_instance(uid, cmd_q, state_q): | ||||
|     logging.basicConfig(filename=f"cocosim.log", filemode="w", level=logging.INFO) | ||||
|     logging.info("Creating instance") | ||||
|     i = CocosimInstance(cmd_q, state_q) | ||||
|     asyncio.run(i.handle_requests()) | ||||
							
								
								
									
										
											BIN
										
									
								
								api_worker/__pycache__/__init__.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										2
									
								
								cocosim.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,2 @@ | ||||
| INFO:root:Creating instance | ||||
| INFO:root:Cocosim instance destroyed | ||||
							
								
								
									
										
											BIN
										
									
								
								images_v1/CoCoSIM_icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 18 KiB | 
							
								
								
									
										83
									
								
								images_v1/CoCoSIM_icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    width="256" | ||||
|    height="256" | ||||
|    viewBox="0 0 256 256" | ||||
|    fill="none" | ||||
|    version="1.1" | ||||
|    id="svg71" | ||||
|    sodipodi:docname="CoCoSIM_icon.svg" | ||||
|    inkscape:export-filename="CoCoSIM_icon.png" | ||||
|    inkscape:export-xdpi="96" | ||||
|    inkscape:export-ydpi="96" | ||||
|    inkscape:version="1.2.2 (732a01da63, 2022-12-09)" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview73" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#000000" | ||||
|      borderopacity="0.25" | ||||
|      inkscape:showpageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#d1d1d1" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="3.3189655" | ||||
|      inkscape:cx="-31.184416" | ||||
|      inkscape:cy="125.49091" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1001" | ||||
|      inkscape:window-x="2391" | ||||
|      inkscape:window-y="-9" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="svg71" /> | ||||
|   <g | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1"> | ||||
|     <rect | ||||
|        style="fill:#000000;stroke-width:4.75706" | ||||
|        id="rect286" | ||||
|        width="256.48053" | ||||
|        height="256.55585" | ||||
|        x="-0.60259742" | ||||
|        y="-0.67792207" /> | ||||
|   </g> | ||||
|   <g | ||||
|      clip-path="url(#clip0_22_80)" | ||||
|      id="g64" | ||||
|      transform="matrix(10.390846,0,0,10.390846,24,3.997707)"> | ||||
|     <path | ||||
|        d="M 2.49756,19.4869 C 2.61625,19.6506 2.581,19.8814 2.41915,20.0014 2.2573,20.1215 2.02926,20.0859 1.91057,19.9221 1.29913,19.0808 0.815726,18.1383 0.487704,17.1252 0.171191,16.1463 -7.32422e-4,15.1012 -7.32422e-4,14.0182 -7.32422e-4,12.4309 0.366854,10.9279 1.02002,9.59315 1.69836,8.20814 2.68459,7.00509 3.88878,6.07641 4.04847,5.95341 4.2765,5.98398 4.39807,6.14555 4.51964,6.30712 4.48943,6.53784 4.32974,6.66084 3.21403,7.52183 2.29974,8.63609 1.67175,9.91848 1.0675,11.1521 0.727966,12.5444 0.727966,14.0175 c 0,1.0065 0.158256,1.9745 0.451034,2.8791 0.30356,0.9382 0.75171,1.8108 1.31784,2.5896 M 18.7649,11.9061 c -0.0454,-0.198 0.0762,-0.3959 0.2719,-0.4425 0.1956,-0.0459 0.3913,0.0771 0.4373,0.2751 0.0849,0.369 0.1504,0.746 0.1936,1.1296 0.0431,0.3799 0.0654,0.7634 0.0654,1.1484 0,2.7562 -1.1042,5.2518 -2.8896,7.059 -1.7854,1.8064 -4.2521,2.9236 -6.97695,2.9236 -0.91573,0 -1.80556,-0.1274 -2.65151,-0.3661 C 6.34391,23.3879 5.52025,23.0233 4.76278,22.5597 4.59158,22.4549 4.53691,22.2285 4.64049,22.0553 4.74408,21.8821 4.9678,21.826 5.139,21.9316 c 0.69993,0.4287 1.46243,0.7656 2.27026,0.9934 0.77905,0.2191 1.60342,0.337 2.45801,0.337 2.52343,0 4.80813,-1.0349 6.46113,-2.7074 1.6538,-1.6732 2.676,-3.984 2.676,-6.5371 0,-0.3632 -0.0201,-0.7191 -0.0597,-1.0648 -0.0403,-0.3552 -0.1007,-0.7038 -0.1791,-1.0459 z" | ||||
|        fill="#ea4c89" | ||||
|        id="path56" /> | ||||
|     <path | ||||
|        d="m 11.0398,4.12735 c -0.2331,-0.23581 -0.556,-0.38137 -0.9136,-0.38137 -0.35748,0 -0.67975,0.14629 -0.91353,0.38283 H 9.21123 c -0.23307,0.2358 -0.37694,0.56259 -0.37694,0.9243 0,0.36172 0.13739,0.67395 0.36111,0.9083 l 0.01727,0.01601 c 0.23378,0.23654 0.55677,0.38283 0.91353,0.38283 0.3568,0 0.6813,-0.14556 0.9136,-0.38137 l 0.0014,-0.00146 c 0.2331,-0.2358 0.377,-0.56259 0.377,-0.92431 0,-0.36171 -0.1439,-0.68922 -0.377,-0.9243 z M 10.1262,3.00799 c 0.5568,0 1.0611,0.22853 1.4279,0.59898 l 0.0022,0.00219 c 0.3654,0.37117 0.5913,0.88136 0.5913,1.44323 0,0.56186 -0.2259,1.0735 -0.592,1.44468 L 11.5534,6.49926 C 11.1866,6.86898 10.6823,7.09751 10.127,7.09751 9.57162,7.09751 9.06376,6.86825 8.69761,6.49853 L 8.67747,6.47597 C 8.32355,6.10697 8.10559,5.60479 8.10559,5.05239 8.10559,4.49998 8.33218,3.97815 8.69833,3.60697 9.06304,3.23579 9.56874,3.00726 10.127,3.00726 Z" | ||||
|        fill="#2ed73c" | ||||
|        id="path58" /> | ||||
|     <path | ||||
|        d="m 7.59772,10.9221 c 0.09135,-0.1812 0.31075,-0.2533 0.48987,-0.1616 0.17912,0.0925 0.25033,0.3145 0.1597,0.4957 L 2.58027,22.5124 C 2.48891,22.6936 2.26951,22.7656 2.0904,22.6739 1.91128,22.5815 1.84006,22.3595 1.9307,22.1783 Z" | ||||
|        fill="#2d7aff" | ||||
|        id="path60" /> | ||||
|     <path | ||||
|        d="m 2.57814,21.9964 h 2.05805 c 3.7406,-1.9251 5.01169,-4.38 4.95702,-6.543 C 9.55005,13.7402 8.68251,12.203 7.56033,11.262 6.48203,10.3581 5.17858,10.016 4.19523,10.6412 L 4.11466,10.695 c -0.01295,0.011 -0.02661,0.0204 -0.041,0.0299 -0.87904,0.6463 -1.50559,2.1113 -1.50559,4.695 H 2.56663 l 0.01079,6.5772 z M 17.2427,14.647 c -7e-4,1.0801 -0.2359,2.0451 -0.2373,2.0524 l -0.0029,0.0124 c -1.4409,5.7707 -5.3527,6.0196 -5.3635,6.0204 l -0.0287,0.0014 H 2.21631 c -0.20142,0 -0.36471,-0.1652 -0.36471,-0.3683 L 1.85304,22.3326 1.84153,15.4199 H 1.84009 c 0,-2.735 0.69201,-4.3755 1.68039,-5.1914 V 8.36753 c 0,-2.23872 0.78481,-4.29549 2.14294,-5.80931 C 6.9791,1.09169 8.83214,0.13609 11.029,0.0167308 14.1388,-0.152119 16.3831,0.991986 17.8527,2.71469 c 0.9402,1.10262 1.5589,2.44032 1.8804,3.81951 0.3209,1.37482 0.3475,2.79621 0.1058,4.0706 -0.3439,1.81 -1.2316,3.3326 -2.5962,4.0422 z M 13.5381,4.88209 c 0,-0.00728 0.0453,-2.36463 2.3825,-2.92504 C 14.6797,1.12081 13.072,0.641185 11.0664,0.750355 9.07312,0.858798 7.39417,1.72488 6.20221,3.05312 4.96493,4.43231 4.2499,6.31295 4.2499,8.3668 V 9.78966 C 5.44689,9.3013 6.86113,9.71688 8.02575,10.6936 c 1.26677,1.0619 2.24585,2.8013 2.29475,4.7416 0.0546,2.1703 -1.04668,4.5837 -4.2003,6.5604 h 5.48 c 0.2647,-0.0247 3.4399,-0.4257 4.6973,-5.4672 0.0302,-0.1259 1.1711,-4.9811 -2.2616,-3.8821 -0.0417,0.0167 -0.087,0.0255 -0.1338,0.0255 -0.2014,0 -0.3647,-0.1653 -0.3647,-0.369 V 4.89228 h 0.0014 z m 3.1745,-2.29986 c -2.3163,0.14556 -2.4415,2.15211 -2.448,2.30932 h 0.0015 v 6.92865 c 2.0516,-0.4832 2.7479,0.6893 2.9256,2.0051 0.9955,-0.6586 1.6552,-1.8981 1.9329,-3.3595 0.223,-1.17541 0.1978,-2.48983 -0.1,-3.76493 C 18.7282,5.43012 18.1621,4.20232 17.3032,3.19577 17.1197,2.98107 16.9234,2.7751 16.7126,2.58223 Z" | ||||
|        fill="#2d7aff" | ||||
|        id="path62" /> | ||||
|   </g> | ||||
|   <defs | ||||
|      id="defs69"> | ||||
|     <clipPath | ||||
|        id="clip0_22_80"> | ||||
|       <rect | ||||
|          width="20" | ||||
|          height="24" | ||||
|          fill="#ffffff" | ||||
|          id="rect66" | ||||
|          x="0" | ||||
|          y="0" /> | ||||
|     </clipPath> | ||||
|   </defs> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 6.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/CoCoSIM_logo_01.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 31 KiB | 
							
								
								
									
										84
									
								
								images_v1/CoCoSIM_logo_01.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/bouton_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										18
									
								
								images_v1/bouton_ferme.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M4.199,50.153 L73.998,45.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M60.429,46.554 L55.564,54.459 L61.854,53.716 L55.92,61.131 L62.505,60.135 L55.974,68.734 C55.974,68.734 62.767,67.244 62.767,67.244" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/bouton_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.5 KiB | 
							
								
								
									
										20
									
								
								images_v1/bouton_ouvert.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M5.417,50.404 L73.417,30.404" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|       <path d="M59.29,36.05 L56.43,45.325 L62.325,42.358 L58.32,51.552 L64.443,48.238 L60.137,58.773 C60.137,58.773 66.345,54.913 66.345,54.913" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/condensateur.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 523 B | 
							
								
								
									
										20
									
								
								images_v1/condensateur.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,50.5 L36.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M44.5,50.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M36.5,30.5 L36.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M44.5,30.5 L44.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/contact_basculeur_droite.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										21
									
								
								images_v1/contact_basculeur_droite.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M70.5,20.5 L38.12,96.229" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M5,38 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M55,38 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M70.5,24.5 C70.5,22.291 72.739,20.5 75.5,20.5 C78.261,20.5 80.5,22.291 80.5,24.5 C80.5,26.709 78.261,28.5 75.5,28.5 C72.739,28.5 70.5,26.709 70.5,24.5 z" fill="#000000"/> | ||||
|       <path d="M70.5,24.5 C70.5,22.291 72.739,20.5 75.5,20.5 C78.261,20.5 80.5,22.291 80.5,24.5 C80.5,26.709 78.261,28.5 75.5,28.5 C72.739,28.5 70.5,26.709 70.5,24.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M32.5,96.5 C32.5,94.291 34.739,92.5 37.5,92.5 C40.261,92.5 42.5,94.291 42.5,96.5 C42.5,98.709 40.261,100.5 37.5,100.5 C34.739,100.5 32.5,98.709 32.5,96.5 z" fill="#000000"/> | ||||
|       <path d="M32.5,96.5 C32.5,94.291 34.739,92.5 37.5,92.5 C40.261,92.5 42.5,94.291 42.5,96.5 C42.5,98.709 40.261,100.5 37.5,100.5 C34.739,100.5 32.5,98.709 32.5,96.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M0.5,24.5 C0.5,22.291 2.739,20.5 5.5,20.5 C8.261,20.5 10.5,22.291 10.5,24.5 C10.5,26.709 8.261,28.5 5.5,28.5 C2.739,28.5 0.5,26.709 0.5,24.5 z" fill="#000000"/> | ||||
|       <path d="M0.5,24.5 C0.5,22.291 2.739,20.5 5.5,20.5 C8.261,20.5 10.5,22.291 10.5,24.5 C10.5,26.709 8.261,28.5 5.5,28.5 C2.739,28.5 0.5,26.709 0.5,24.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/contact_basculeur_gauche.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										21
									
								
								images_v1/contact_basculeur_gauche.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M10.5,20.5 L38.12,96.229" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M5,38 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M55,38 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M70.5,24.5 C70.5,22.291 72.739,20.5 75.5,20.5 C78.261,20.5 80.5,22.291 80.5,24.5 C80.5,26.709 78.261,28.5 75.5,28.5 C72.739,28.5 70.5,26.709 70.5,24.5 z" fill="#000000"/> | ||||
|       <path d="M70.5,24.5 C70.5,22.291 72.739,20.5 75.5,20.5 C78.261,20.5 80.5,22.291 80.5,24.5 C80.5,26.709 78.261,28.5 75.5,28.5 C72.739,28.5 70.5,26.709 70.5,24.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M32.5,96.5 C32.5,94.291 34.739,92.5 37.5,92.5 C40.261,92.5 42.5,94.291 42.5,96.5 C42.5,98.709 40.261,100.5 37.5,100.5 C34.739,100.5 32.5,98.709 32.5,96.5 z" fill="#000000"/> | ||||
|       <path d="M32.5,96.5 C32.5,94.291 34.739,92.5 37.5,92.5 C40.261,92.5 42.5,94.291 42.5,96.5 C42.5,98.709 40.261,100.5 37.5,100.5 C34.739,100.5 32.5,98.709 32.5,96.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M0.5,24.5 C0.5,22.291 2.739,20.5 5.5,20.5 C8.261,20.5 10.5,22.291 10.5,24.5 C10.5,26.709 8.261,28.5 5.5,28.5 C2.739,28.5 0.5,26.709 0.5,24.5 z" fill="#000000"/> | ||||
|       <path d="M0.5,24.5 C0.5,22.291 2.739,20.5 5.5,20.5 C8.261,20.5 10.5,22.291 10.5,24.5 C10.5,26.709 8.261,28.5 5.5,28.5 C2.739,28.5 0.5,26.709 0.5,24.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/contact_double_repos.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										21
									
								
								images_v1/contact_double_repos.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,60.5 L76.5,49" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,40.5 C2.291,40.5 0.5,38.261 0.5,35.5 C0.5,32.739 2.291,30.5 4.5,30.5 C6.709,30.5 8.5,32.739 8.5,35.5 C8.5,38.261 6.709,40.5 4.5,40.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,40.5 C2.291,40.5 0.5,38.261 0.5,35.5 C0.5,32.739 2.291,30.5 4.5,30.5 C6.709,30.5 8.5,32.739 8.5,35.5 C8.5,38.261 6.709,40.5 4.5,40.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M4.5,70.5 C2.291,70.5 0.5,68.261 0.5,65.5 C0.5,62.739 2.291,60.5 4.5,60.5 C6.709,60.5 8.5,62.739 8.5,65.5 C8.5,68.261 6.709,70.5 4.5,70.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,70.5 C2.291,70.5 0.5,68.261 0.5,65.5 C0.5,62.739 2.291,60.5 4.5,60.5 C6.709,60.5 8.5,62.739 8.5,65.5 C8.5,68.261 6.709,70.5 4.5,70.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/contact_double_travail.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1014 B | 
							
								
								
									
										21
									
								
								images_v1/contact_double_travail.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,40.5 L76.5,49" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,40.5 C2.291,40.5 0.5,38.261 0.5,35.5 C0.5,32.739 2.291,30.5 4.5,30.5 C6.709,30.5 8.5,32.739 8.5,35.5 C8.5,38.261 6.709,40.5 4.5,40.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,40.5 C2.291,40.5 0.5,38.261 0.5,35.5 C0.5,32.739 2.291,30.5 4.5,30.5 C6.709,30.5 8.5,32.739 8.5,35.5 C8.5,38.261 6.709,40.5 4.5,40.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M4.5,70.5 C2.291,70.5 0.5,68.261 0.5,65.5 C0.5,62.739 2.291,60.5 4.5,60.5 C6.709,60.5 8.5,62.739 8.5,65.5 C8.5,68.261 6.709,70.5 4.5,70.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,70.5 C2.291,70.5 0.5,68.261 0.5,65.5 C0.5,62.739 2.291,60.5 4.5,60.5 C6.709,60.5 8.5,62.739 8.5,65.5 C8.5,68.261 6.709,70.5 4.5,70.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/diode_dg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 713 B | 
							
								
								
									
										22
									
								
								images_v1/diode_dg.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M76.5,50.5 L4.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M68.5,0.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M68.5,50.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M24.5,76.5 L24.5,25.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <g> | ||||
|       <path d="M56.5,75.5 L24.5,50.5 L56.5,25.5 L56.5,75.5 z" fill="#000000"/> | ||||
|       <path d="M56.5,75.5 L24.5,50.5 L56.5,25.5 L56.5,75.5 z" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linejoin="bevel"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/diode_gd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 782 B | 
							
								
								
									
										22
									
								
								images_v1/diode_gd.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,50.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M56.5,25.5 L56.5,75.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <g> | ||||
|       <path d="M24.5,25.5 L56.5,50.5 L24.5,75.5 z" fill="#000000"/> | ||||
|       <path d="M24.5,25.5 L56.5,50.5 L24.5,75.5 z" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linejoin="bevel"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/lampe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										22
									
								
								images_v1/lampe.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M5.5,55.5 C2.739,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.739,45.5 5.5,45.5 C8.261,45.5 10.5,47.739 10.5,50.5 C10.5,53.261 8.261,55.5 5.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M5.5,55.5 C2.739,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.739,45.5 5.5,45.5 C8.261,45.5 10.5,47.739 10.5,50.5 C10.5,53.261 8.261,55.5 5.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M75.5,55.5 C72.739,55.5 70.5,53.261 70.5,50.5 C70.5,47.739 72.739,45.5 75.5,45.5 C78.261,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.261,55.5 75.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M75.5,55.5 C72.739,55.5 70.5,53.261 70.5,50.5 C70.5,47.739 72.739,45.5 75.5,45.5 C78.261,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.261,55.5 75.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M40.5,80.5 C23.931,80.5 10.5,67.069 10.5,50.5 C10.5,33.931 23.931,20.5 40.5,20.5 C57.069,20.5 70.5,33.931 70.5,50.5 C70.5,67.069 57.069,80.5 40.5,80.5 z" fill="#FFFFFF"/> | ||||
|       <path d="M40.5,80.5 C23.931,80.5 10.5,67.069 10.5,50.5 C10.5,33.931 23.931,20.5 40.5,20.5 C57.069,20.5 70.5,33.931 70.5,50.5 C70.5,67.069 57.069,80.5 40.5,80.5 z" fill-opacity="0" stroke="#000000" stroke-width="2.7"/> | ||||
|     </g> | ||||
|     <path d="M20.5,70.5 L60.5,30.5" fill-opacity="0" stroke="#000000" stroke-width="2" stroke-linecap="round"/> | ||||
|     <path d="M20.5,30.5 L60.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2" stroke-linecap="round"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/levier_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										100
									
								
								images_v1/levier_ferme.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,100 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    version="1.1" | ||||
|    x="0" | ||||
|    y="0" | ||||
|    width="80" | ||||
|    height="100" | ||||
|    viewBox="0, 0, 80, 100" | ||||
|    id="svg10" | ||||
|    sodipodi:docname="levier_ouvert.svg" | ||||
|    inkscape:version="1.3-beta (cedbd6c, 2023-05-28)" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <defs | ||||
|      id="defs10" /> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview10" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#000000" | ||||
|      borderopacity="0.25" | ||||
|      inkscape:showpageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#d1d1d1" | ||||
|      inkscape:zoom="8.2929269" | ||||
|      inkscape:cx="33.884297" | ||||
|      inkscape:cy="51.972001" | ||||
|      inkscape:window-width="1710" | ||||
|      inkscape:window-height="1069" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="38" | ||||
|      inkscape:window-maximized="0" | ||||
|      inkscape:current-layer="svg10" /> | ||||
|   <path | ||||
|      d="M 12.5,101.5 Z" | ||||
|      fill-opacity="0" | ||||
|      stroke="#000000" | ||||
|      stroke-width="0.9" | ||||
|      id="path1" /> | ||||
|   <path | ||||
|      d="M 12.5,51.5 Z" | ||||
|      fill-opacity="0" | ||||
|      stroke="#000000" | ||||
|      stroke-width="0.9" | ||||
|      id="path2" /> | ||||
|   <g | ||||
|      id="g4"> | ||||
|     <path | ||||
|        d="m 5.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill="#000000" | ||||
|        id="path3" /> | ||||
|     <path | ||||
|        d="m 5.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path4" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g6" | ||||
|      transform="translate(-0.72350814)"> | ||||
|     <path | ||||
|        d="m 75.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill="#000000" | ||||
|        id="path5" /> | ||||
|     <path | ||||
|        d="m 75.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path6" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g8"> | ||||
|     <path | ||||
|        d="m 40.5,80.5 c -16.569,0 -30,-13.431 -30,-30 0,-16.569 13.431,-30 30,-30 16.569,0 30,13.431 30,30 0,16.569 -13.431,30 -30,30 z" | ||||
|        fill="#ffffff" | ||||
|        id="path7" /> | ||||
|     <path | ||||
|        d="m 40.5,80.5 c -16.569,0 -30,-13.431 -30,-30 0,-16.569 13.431,-30 30,-30 16.569,0 30,13.431 30,30 0,16.569 -13.431,30 -30,30 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="2.7" | ||||
|        id="path8" /> | ||||
|   </g> | ||||
|   <path | ||||
|      style="fill:#121212;stroke:#000000;stroke-width:4.41824" | ||||
|      id="path11" | ||||
|      sodipodi:type="arc" | ||||
|      sodipodi:cx="40.160213" | ||||
|      sodipodi:cy="49.300335" | ||||
|      sodipodi:rx="29.252346" | ||||
|      sodipodi:ry="27.2386" | ||||
|      sodipodi:start="3.1415927" | ||||
|      sodipodi:end="0" | ||||
|      sodipodi:arc-type="slice" | ||||
|      d="m 10.907867,49.300335 a 29.252346,27.2386 0 0 1 29.252346,-27.2386 29.252346,27.2386 0 0 1 29.252347,27.2386 H 40.160213 Z" /> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/levier_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										106
									
								
								images_v1/levier_ouvert.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,106 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    version="1.1" | ||||
|    x="0" | ||||
|    y="0" | ||||
|    width="80" | ||||
|    height="100" | ||||
|    viewBox="0, 0, 80, 100" | ||||
|    id="svg10" | ||||
|    sodipodi:docname="levier_ferme.svg" | ||||
|    inkscape:version="1.3-beta (cedbd6c, 2023-05-28)" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <defs | ||||
|      id="defs10" /> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview10" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#000000" | ||||
|      borderopacity="0.25" | ||||
|      inkscape:showpageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#d1d1d1" | ||||
|      inkscape:zoom="8.2929269" | ||||
|      inkscape:cx="33.884297" | ||||
|      inkscape:cy="51.972001" | ||||
|      inkscape:window-width="1710" | ||||
|      inkscape:window-height="1069" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="38" | ||||
|      inkscape:window-maximized="0" | ||||
|      inkscape:current-layer="svg10" /> | ||||
|   <path | ||||
|      d="M 12.5,101.5 Z" | ||||
|      fill-opacity="0" | ||||
|      stroke="#000000" | ||||
|      stroke-width="0.9" | ||||
|      id="path1" /> | ||||
|   <path | ||||
|      d="M 12.5,51.5 Z" | ||||
|      fill-opacity="0" | ||||
|      stroke="#000000" | ||||
|      stroke-width="0.9" | ||||
|      id="path2" /> | ||||
|   <g | ||||
|      id="g4"> | ||||
|     <path | ||||
|        d="m 5.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill="#000000" | ||||
|        id="path3" /> | ||||
|     <path | ||||
|        d="m 5.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path4" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g6"> | ||||
|     <path | ||||
|        d="m 75.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill="#000000" | ||||
|        id="path5" /> | ||||
|     <path | ||||
|        d="m 75.5,55.5 c -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path6" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g8"> | ||||
|     <path | ||||
|        d="m 40.5,80.5 c -16.569,0 -30,-13.431 -30,-30 0,-16.569 13.431,-30 30,-30 16.569,0 30,13.431 30,30 0,16.569 -13.431,30 -30,30 z" | ||||
|        fill="#ffffff" | ||||
|        id="path7" /> | ||||
|     <path | ||||
|        d="m 40.5,80.5 c -16.569,0 -30,-13.431 -30,-30 0,-16.569 13.431,-30 30,-30 16.569,0 30,13.431 30,30 0,16.569 -13.431,30 -30,30 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="2.7" | ||||
|        id="path8" /> | ||||
|   </g> | ||||
|   <path | ||||
|      d="m 20.5,70.5 40,-40" | ||||
|      fill-opacity="0" | ||||
|      stroke="#000000" | ||||
|      stroke-width="2" | ||||
|      stroke-linecap="round" | ||||
|      id="path9" /> | ||||
|   <path | ||||
|      style="fill:#121212;stroke:#000000;stroke-width:4.41824" | ||||
|      id="path11" | ||||
|      sodipodi:type="arc" | ||||
|      sodipodi:cx="40.160213" | ||||
|      sodipodi:cy="49.300335" | ||||
|      sodipodi:rx="29.252346" | ||||
|      sodipodi:ry="27.2386" | ||||
|      sodipodi:start="2.3561945" | ||||
|      sodipodi:end="5.4925512" | ||||
|      sodipodi:arc-type="slice" | ||||
|      d="M 19.475681,68.560933 A 29.252346,27.2386 0 0 1 19.421601,30.090226 29.252346,27.2386 0 0 1 60.73616,29.939153 L 40.160213,49.300335 Z" /> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_bouton_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_bouton_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_contact_double_repos.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 684 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_contact_double_travail.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 610 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_moins.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 316 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_plus.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_pulse.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										18
									
								
								images_v1/mirror_pulse.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <text transform="matrix(1, 0, 0, 1, 44.212, 50)"> | ||||
|       <tspan x="-20.012" y="5.5" font-family="Helvetica" font-size="16" fill="#000000">Pulsé</tspan> | ||||
|     </text> | ||||
|     <text transform="matrix(1, 0, 0, 1, 47.2, 33.5)"> | ||||
|       <tspan x="-24.427" y="6.5" font-family="Helvetica" font-size="28.8" fill="#000000">+24</tspan> | ||||
|     </text> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_relais_cote.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_repos_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 645 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_repos_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 431 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_travail_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 508 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/mirror_travail_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 714 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/moins.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 661 B | 
							
								
								
									
										15
									
								
								images_v1/moins.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <text transform="matrix(1, 0, 0, 1, 22.837, 29)"> | ||||
|       <tspan x="-8.991" y="12" font-family="Helvetica" font-size="54" fill="#000000">-</tspan> | ||||
|     </text> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/noeud.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 594 B | 
							
								
								
									
										12
									
								
								images_v1/noeud.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M40.5,55.5 C38.291,55.5 36.5,53.261 36.5,50.5 C36.5,47.739 38.291,45.5 40.5,45.5 C42.709,45.5 44.5,47.739 44.5,50.5 C44.5,53.261 42.709,55.5 40.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M40.5,55.5 C38.291,55.5 36.5,53.261 36.5,50.5 C36.5,47.739 38.291,45.5 40.5,45.5 C42.709,45.5 44.5,47.739 44.5,50.5 C44.5,53.261 42.709,55.5 40.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 921 B | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/plus.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.2 KiB | 
							
								
								
									
										15
									
								
								images_v1/plus.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <text transform="matrix(1, 0, 0, 1, 47.2, 33.5)"> | ||||
|       <tspan x="-24.427" y="6.5" font-family="Helvetica" font-size="28.8" fill="#000000">+24</tspan> | ||||
|     </text> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/pulse.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										18
									
								
								images_v1/pulse.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <text transform="matrix(1, 0, 0, 1, 47.2, 33.5)"> | ||||
|       <tspan x="-24.427" y="6.5" font-family="Helvetica" font-size="28.8" fill="#000000">+24</tspan> | ||||
|     </text> | ||||
|     <text transform="matrix(1, 0, 0, 1, 44.212, 50)"> | ||||
|       <tspan x="-20.012" y="5.5" font-family="Helvetica" font-size="16" fill="#000000">Pulsé</tspan> | ||||
|     </text> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/relais.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										22
									
								
								images_v1/relais.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <g> | ||||
|       <path d="M8.5,10.5 L72.5,10.5 L72.5,90.5 L8.5,90.5 z" fill="#FFFFFF"/> | ||||
|       <path d="M8.5,10.5 L72.5,10.5 L72.5,90.5 L8.5,90.5 z" fill-opacity="0" stroke="#000000" stroke-width="4.05"/> | ||||
|     </g> | ||||
|     <path d="M8.5,30.5 L40.5,60.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M40.5,60.5 L72.5,30.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/relais_basculeur.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										46
									
								
								images_v1/relais_basculeur.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,46 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="160" height="100" viewBox="0, 0, 160, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <g> | ||||
|       <path d="M5,30.385 C2.239,30.385 0,28.189 0,25.481 C0,22.773 2.239,20.577 5,20.577 C7.761,20.577 10,22.773 10,25.481 C10,28.189 7.761,30.385 5,30.385 z" fill="#000000"/> | ||||
|       <path d="M5,30.385 C2.239,30.385 0,28.189 0,25.481 C0,22.773 2.239,20.577 5,20.577 C7.761,20.577 10,22.773 10,25.481 C10,28.189 7.761,30.385 5,30.385 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <g> | ||||
|         <g> | ||||
|           <path d="M9.678,8.5 L72.586,8.5 L72.586,88.5 L9.678,88.5 z" fill="#FFFFFF"/> | ||||
|           <path d="M9.678,8.5 L72.586,8.5 L72.586,88.5 L9.678,88.5 z" fill-opacity="0" stroke="#000000" stroke-width="4.05"/> | ||||
|         </g> | ||||
|         <path d="M9.678,28.5 L41.132,58.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|         <path d="M41.132,58.5 L72.586,28.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|       </g> | ||||
|       <path d="M0,100 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|       <path d="M0,50 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|       <g> | ||||
|         <g> | ||||
|           <path d="M87.103,8.5 L150.011,8.5 L150.011,88.5 L87.103,88.5 z" fill="#FFFFFF"/> | ||||
|           <path d="M87.103,8.5 L150.011,8.5 L150.011,88.5 L87.103,88.5 z" fill-opacity="0" stroke="#000000" stroke-width="4.05"/> | ||||
|         </g> | ||||
|         <path d="M87.103,28.5 L118.557,58.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|         <path d="M118.557,58.5 L150.011,28.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|       </g> | ||||
|       <g> | ||||
|         <path d="M70.378,8.5 L88.429,8.5 L88.429,88.5 L70.378,88.5 L70.378,8.5 z" fill="#000000"/> | ||||
|         <path d="M70.378,8.5 L88.429,8.5 L88.429,88.5 L70.378,88.5 L70.378,8.5 z" fill-opacity="0" stroke="#000000" stroke-width="1"/> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M5,69.916 C2.239,69.916 -0,67.677 -0,64.916 C-0,62.155 2.239,59.916 5,59.916 C7.761,59.916 10,62.155 10,64.916 C10,67.677 7.761,69.916 5,69.916 z" fill="#000000"/> | ||||
|       <path d="M5,69.916 C2.239,69.916 -0,67.677 -0,64.916 C-0,62.155 2.239,59.916 5,59.916 C7.761,59.916 10,62.155 10,64.916 C10,67.677 7.761,69.916 5,69.916 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M155.005,30.385 C152.247,30.385 150.011,28.146 150.011,25.385 C150.011,22.624 152.247,20.385 155.005,20.385 C157.764,20.385 160,22.624 160,25.385 C160,28.146 157.764,30.385 155.005,30.385 z" fill="#000000"/> | ||||
|       <path d="M155.005,30.385 C152.247,30.385 150.011,28.146 150.011,25.385 C150.011,22.624 152.247,20.385 155.005,20.385 C157.764,20.385 160,22.624 160,25.385 C160,28.146 157.764,30.385 155.005,30.385 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M155.005,69.916 C152.247,69.916 150.011,67.677 150.011,64.916 C150.011,62.155 152.247,59.916 155.005,59.916 C157.764,59.916 160,62.155 160,64.916 C160,67.677 157.764,69.916 155.005,69.916 z" fill="#000000"/> | ||||
|       <path d="M155.005,69.916 C152.247,69.916 150.011,67.677 150.011,64.916 C150.011,62.155 152.247,59.916 155.005,59.916 C157.764,59.916 160,62.155 160,64.916 C160,67.677 157.764,69.916 155.005,69.916 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/relais_cote.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										107
									
								
								images_v1/relais_cote.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,107 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    version="1.1" | ||||
|    x="0" | ||||
|    y="0" | ||||
|    width="80" | ||||
|    height="100" | ||||
|    viewBox="0, 0, 80, 100" | ||||
|    id="svg29" | ||||
|    sodipodi:docname="relais_cote.svg" | ||||
|    inkscape:version="1.2.2 (732a01da63, 2022-12-09)" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <defs | ||||
|      id="defs33" /> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview31" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#000000" | ||||
|      borderopacity="0.25" | ||||
|      inkscape:showpageshadow="2" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#d1d1d1" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="8.14" | ||||
|      inkscape:cx="37.100737" | ||||
|      inkscape:cy="50.061425" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1001" | ||||
|      inkscape:window-x="-9" | ||||
|      inkscape:window-y="-9" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="svg29" /> | ||||
|   <g | ||||
|      id="Layer_1"> | ||||
|     <g | ||||
|        id="g6"> | ||||
|       <path | ||||
|          d="M8.5,10.5 L72.5,10.5 L72.5,90.5 L8.5,90.5 z" | ||||
|          fill="#FFFFFF" | ||||
|          id="path2" /> | ||||
|       <path | ||||
|          d="M8.5,10.5 L72.5,10.5 L72.5,90.5 L8.5,90.5 z" | ||||
|          fill-opacity="0" | ||||
|          stroke="#000000" | ||||
|          stroke-width="4.05" | ||||
|          id="path4" /> | ||||
|     </g> | ||||
|     <path | ||||
|        d="M8.5,30.5 L40.5,60.5" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="2.7" | ||||
|        stroke-linecap="round" | ||||
|        id="path8" /> | ||||
|     <path | ||||
|        d="M40.5,60.5 L72.5,30.5" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="2.7" | ||||
|        stroke-linecap="round" | ||||
|        id="path10" /> | ||||
|     <path | ||||
|        d="M12.5,101.5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path12" /> | ||||
|     <path | ||||
|        d="M12.5,51.5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path14" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g26" | ||||
|      transform="translate(-71.954546,-22.40172)"> | ||||
|     <path | ||||
|        d="m 76.5,55.5 c -2.209,0 -4,-2.239 -4,-5 0,-2.761 1.791,-5 4,-5 2.209,0 4,2.239 4,5 0,2.761 -1.791,5 -4,5 z" | ||||
|        fill="#000000" | ||||
|        id="path22" /> | ||||
|     <path | ||||
|        d="m 76.5,55.5 c -2.209,0 -4,-2.239 -4,-5 0,-2.761 1.791,-5 4,-5 2.209,0 4,2.239 4,5 0,2.761 -1.791,5 -4,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path24" /> | ||||
|   </g> | ||||
|   <g | ||||
|      id="g20" | ||||
|      transform="translate(0.07985261,18.114251)"> | ||||
|     <path | ||||
|        d="m 4.5,55.5 c -2.209,0 -4,-2.239 -4,-5 0,-2.761 1.791,-5 4,-5 2.209,0 4,2.239 4,5 0,2.761 -1.791,5 -4,5 z" | ||||
|        fill="#000000" | ||||
|        id="path16" /> | ||||
|     <path | ||||
|        d="m 4.5,55.5 c -2.209,0 -4,-2.239 -4,-5 0,-2.761 1.791,-5 4,-5 2.209,0 4,2.239 4,5 0,2.761 -1.791,5 -4,5 z" | ||||
|        fill-opacity="0" | ||||
|        stroke="#000000" | ||||
|        stroke-width="0.9" | ||||
|        id="path18" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/repos_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										23
									
								
								images_v1/repos_ferme.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,65.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M16.5,75.5 C14.291,75.5 12.5,73.261 12.5,70.5 C12.5,67.739 14.291,65.5 16.5,65.5 C18.709,65.5 20.5,67.739 20.5,70.5 C20.5,73.261 18.709,75.5 16.5,75.5 z" fill="#000000"/> | ||||
|       <path d="M16.5,75.5 C14.291,75.5 12.5,73.261 12.5,70.5 C12.5,67.739 14.291,65.5 16.5,65.5 C18.709,65.5 20.5,67.739 20.5,70.5 C20.5,73.261 18.709,75.5 16.5,75.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M4.5,50.5 L4.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M4.5,70.5 L16.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/repos_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 829 B | 
							
								
								
									
										23
									
								
								images_v1/repos_ouvert.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M16.5,50.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M16.5,75.5 C14.291,75.5 12.5,73.261 12.5,70.5 C12.5,67.739 14.291,65.5 16.5,65.5 C18.709,65.5 20.5,67.739 20.5,70.5 C20.5,73.261 18.709,75.5 16.5,75.5 z" fill="#000000"/> | ||||
|       <path d="M16.5,75.5 C14.291,75.5 12.5,73.261 12.5,70.5 C12.5,67.739 14.291,65.5 16.5,65.5 C18.709,65.5 20.5,67.739 20.5,70.5 C20.5,73.261 18.709,75.5 16.5,75.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M4.5,50.5 L4.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M4.5,70.5 L16.5,70.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/resistance.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 561 B | 
							
								
								
									
										19
									
								
								images_v1/resistance.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,50.5 L20.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M60.5,50.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="2.7" stroke-linecap="round"/> | ||||
|     <path d="M20.5,50.5 C20.5,50.5 20.5,35.5 20.5,35.5 L28.5,35.5 C28.5,35.5 28.5,65.5 28.5,65.5 C28.5,65.5 36.5,65.5 36.5,65.5 L36.5,35.5 L44.5,35.5 L44.5,65.5 L52.5,65.5 L52.5,35.5 L60.5,35.5 L60.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="2.7"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/tempo_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										25
									
								
								images_v1/tempo_ferme.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,25 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M4.199,50.153 L73.998,45.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M40.5,36.9 C35.033,36.9 30.601,31.489 30.601,24.815 C30.601,18.14 35.033,12.729 40.5,12.729 C45.967,12.729 50.399,18.14 50.399,24.815 C50.399,31.489 45.967,36.9 40.5,36.9 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M38.5,12.729 L38.5,7.729 L42.5,7.729 L42.5,12.729" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M45.682,14.113 L46.788,12.224 L48.304,13.611 L47.198,15.5" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M40.5,26.539 C40.044,26.539 39.674,26.075 39.674,25.503 C39.674,24.93 40.044,24.466 40.5,24.466 C40.956,24.466 41.326,24.93 41.326,25.503 C41.326,26.075 40.956,26.539 40.5,26.539 z" fill="#000000"/> | ||||
|       <path d="M40.5,26.539 C40.044,26.539 39.674,26.075 39.674,25.503 C39.674,24.93 40.044,24.466 40.5,24.466 C40.956,24.466 41.326,24.93 41.326,25.503 C41.326,26.075 40.956,26.539 40.5,26.539 z" fill-opacity="0" stroke="#000000" stroke-width="0.9" stroke-linejoin="bevel"/> | ||||
|     </g> | ||||
|     <path d="M40.521,16.651 L40.474,25.251" fill-opacity="0" stroke="#000000" stroke-width="0.9" stroke-linejoin="bevel"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/tempo_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										25
									
								
								images_v1/tempo_ouvert.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,25 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <path d="M4.199,50.153 L74.515,31.649" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M40.5,36.9 C35.033,36.9 30.601,31.489 30.601,24.815 C30.601,18.14 35.033,12.729 40.5,12.729 C45.967,12.729 50.399,18.14 50.399,24.815 C50.399,31.489 45.967,36.9 40.5,36.9 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M38.5,12.729 L38.5,7.729 L42.5,7.729 L42.5,12.729" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M45.682,14.113 L46.788,12.224 L48.304,13.611 L47.198,15.5" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M40.5,26.539 C40.044,26.539 39.674,26.075 39.674,25.503 C39.674,24.93 40.044,24.466 40.5,24.466 C40.956,24.466 41.326,24.93 41.326,25.503 C41.326,26.075 40.956,26.539 40.5,26.539 z" fill="#000000"/> | ||||
|       <path d="M40.5,26.539 C40.044,26.539 39.674,26.075 39.674,25.503 C39.674,24.93 40.044,24.466 40.5,24.466 C40.956,24.466 41.326,24.93 41.326,25.503 C41.326,26.075 40.956,26.539 40.5,26.539 z" fill-opacity="0" stroke="#000000" stroke-width="0.9" stroke-linejoin="bevel"/> | ||||
|     </g> | ||||
|     <path d="M40.521,16.651 L40.474,25.251" fill-opacity="0" stroke="#000000" stroke-width="0.9" stroke-linejoin="bevel"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/travail_ferme.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 857 B | 
							
								
								
									
										17
									
								
								images_v1/travail_ferme.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M8.5,75.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images_v1/travail_ouvert.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										17
									
								
								images_v1/travail_ouvert.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="80" height="100" viewBox="0, 0, 80, 100"> | ||||
|   <g id="Layer_1"> | ||||
|     <path d="M4.5,55.5 L76.5,50.5" fill-opacity="0" stroke="#000000" stroke-width="4.5" stroke-linecap="round"/> | ||||
|     <path d="M12.5,101.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <path d="M12.5,51.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     <g> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M4.5,55.5 C2.291,55.5 0.5,53.261 0.5,50.5 C0.5,47.739 2.291,45.5 4.5,45.5 C6.709,45.5 8.5,47.739 8.5,50.5 C8.5,53.261 6.709,55.5 4.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|     <g> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill="#000000"/> | ||||
|       <path d="M76.5,55.5 C74.291,55.5 72.5,53.261 72.5,50.5 C72.5,47.739 74.291,45.5 76.5,45.5 C78.709,45.5 80.5,47.739 80.5,50.5 C80.5,53.261 78.709,55.5 76.5,55.5 z" fill-opacity="0" stroke="#000000" stroke-width="0.9"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/cocosim.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/composants.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/donnees.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/elements.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/exceptions.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/graphe.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								modele/__pycache__/matrice.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										52
									
								
								modele/cocosim.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,52 @@ | ||||
| from modele.matrice import Matrice | ||||
|  | ||||
|  | ||||
| class Cocosim(object): | ||||
|     def __init__(self, conf, graphe, scenario, observateur): | ||||
|         self.conf = conf | ||||
|         self.graphe = graphe | ||||
|         self.scenario = scenario | ||||
|         if 'max' in self.scenario: | ||||
|             self.max_cycles = self.scenario['max'] | ||||
|         else: | ||||
|             self.max_cycles = None | ||||
|         self.n_cycle = 0 | ||||
|         self.matrice = Matrice(self.graphe) | ||||
|         self.observatoire = {} | ||||
|         self.observateur = observateur | ||||
|         for k,_,_ in self.observateur: | ||||
|             self.observatoire[k] = [] | ||||
|  | ||||
|     def cycle(self): | ||||
|         """ | ||||
|         Un cycle se fait en deux passes plus la mise à jour des composants. | ||||
|         """ | ||||
|         if self.n_cycle in self.scenario: | ||||
|             [f(self.graphe[x]) for x, f in self.scenario[self.n_cycle]] | ||||
|  | ||||
|         self.graphe.init_cycle() | ||||
|  | ||||
|         # Passe 1 | ||||
|         self.matrice.init_mat() | ||||
|         xvect = self.matrice.solve() | ||||
|         self.graphe.passe_calcul(xvect) | ||||
|  | ||||
|         # Passe 2 (pour les diodes) | ||||
|         self.matrice.init_mat() | ||||
|         xvect = self.matrice.solve() | ||||
|         self.graphe.passe_calcul(xvect) | ||||
|  | ||||
|         # Mise à jour des états | ||||
|         self.graphe.update() | ||||
|         self.graphe.coherence() | ||||
|  | ||||
|         for k, obj, fun in self.observateur: | ||||
|             self.observatoire[k].append(fun(self.graphe[obj])) | ||||
|  | ||||
|         self.n_cycle += 1 | ||||
|  | ||||
|     def run(self): | ||||
|         for cycle in range(self.max_cycles): | ||||
|             self.cycle() | ||||
|  | ||||
|  | ||||
							
								
								
									
										273
									
								
								modele/composants.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,273 @@ | ||||
| from modele.exceptions import NonPolariseException, Dir | ||||
|  | ||||
| class Composant(object): | ||||
|     def __init__(self, conf, nom): | ||||
|         """ | ||||
|         Un composant doit a minima savoir donner une résistance | ||||
|         """ | ||||
|         self.branche = None  # Pour récupérer l'intensité dans la branche | ||||
|         self.nom = nom | ||||
|         self.conf = conf | ||||
|         self.r = None | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         """ | ||||
|         Initialisation du composant avant la 1ere passe de calcul. | ||||
|         Pour la plupart des composants (ceux qui se calculent en une seule passe) on ne fait | ||||
|         rien. N'est utile que pour les composants se calculant en plusieurs passes (diodes...). | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def passe_calcul(self): | ||||
|         """ | ||||
|         Initialisation du composant apres la 1ere passe de calcul. | ||||
|         Pour la plupart des composants (ceux qui se calculent en une seule passe) on ne fait | ||||
|         rien. N'est utile que pour les composants se calculant en plusieurs passes (diodes...).        """ | ||||
|         pass | ||||
|  | ||||
|     def update(self): | ||||
|         # Par défaut ne fait rien | ||||
|         pass | ||||
|  | ||||
|     def reverse(self): | ||||
|         """ | ||||
|         Permet de retourner les composants polarisés (s'ils sont préfixés par "!") | ||||
|         """ | ||||
|         raise NonPolariseException | ||||
|  | ||||
|     def etat(self): | ||||
|         raise NotImplementedError | ||||
|      | ||||
|     def pause_simulation(self): | ||||
|  | ||||
|         pass | ||||
|  | ||||
|  | ||||
| class Contact(Composant): | ||||
|     def __init__(self, conf, nom, contact_type): | ||||
|         super().__init__(conf, nom) | ||||
|         self.ouvert = None | ||||
|         self.ouvre() | ||||
|         self.type = contact_type | ||||
|  | ||||
|     def ouvre(self): | ||||
|         self.ouvert = True | ||||
|         self.r = self.conf['RMAX'] | ||||
|  | ||||
|     def ferme(self): | ||||
|         self.ouvert = False | ||||
|         self.r = self.conf['RMIN'] | ||||
|  | ||||
|     def etat(self): | ||||
|         return not self.ouvert | ||||
|  | ||||
|     def bascule(self): | ||||
|         if self.ouvert: | ||||
|             self.ferme() | ||||
|         else: | ||||
|             self.ouvre() | ||||
|  | ||||
|  | ||||
| class Resistance(Composant): | ||||
|     def __init__(self, conf, nom, valeur): | ||||
|         super().__init__(conf, nom) | ||||
|         self.RDEFAULT = self.conf["RES_DEFAULT"] | ||||
|         if valeur is None: | ||||
|             self.r = self.RDEFAULT | ||||
|         else: | ||||
|             self.r = valeur | ||||
|  | ||||
|     def set_r(self, valeur): | ||||
|         self.r = valeur | ||||
|  | ||||
|     def etat(self): | ||||
|         return None | ||||
|  | ||||
|  | ||||
| class Lampe(Resistance): | ||||
|     def __init__(self, conf, nom): | ||||
|         self.RLAMPE = conf["RES_LAMPE"] | ||||
|         self.SEUIL = conf["SEUIL_LAMPE"] | ||||
|         super().__init__(conf, nom, self.RLAMPE) | ||||
|         self.haut = False | ||||
|         self.chute() | ||||
|  | ||||
|     def monte(self): | ||||
|         self.haut = True | ||||
|  | ||||
|     def chute(self): | ||||
|         self.haut = False | ||||
|  | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         if abs(self.branche.i()) >= self.SEUIL: | ||||
|             self.monte() | ||||
|         else: | ||||
|             self.chute() | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.haut | ||||
|  | ||||
|  | ||||
| class Relais(Composant): | ||||
|     def __init__(self, conf, nom, graphe): | ||||
|         super().__init__(conf, nom) | ||||
|         self.graphe = graphe | ||||
|         self.r = self.conf["RES_RELAIS"] | ||||
|         self.SEUIL = self.conf["SEUIL_RELAIS"] | ||||
|         prefix = nom.split('.') | ||||
|         self._contacts_travail = [] | ||||
|         self._contacts_repos = [] | ||||
|         self._contacts_double = [] | ||||
|         self.haut = False | ||||
|         self.etat_precedent = False #etat precedent du relais | ||||
|         self.est_point_arret = False   #indicateur de point d'arret | ||||
|  | ||||
|     def add_travail(self, nom): | ||||
|         self._contacts_travail.append(nom) | ||||
|  | ||||
|     def add_repos(self, nom): | ||||
|         self._contacts_repos.append(nom) | ||||
|  | ||||
|     def add_double(self, nom): | ||||
|         self._contacts_double.append(nom) | ||||
|  | ||||
|     def monte(self): | ||||
|         self.haut = True | ||||
|         for nom in self._contacts_repos: | ||||
|             self.graphe[nom].ouvre() | ||||
|  | ||||
|         for nom in self._contacts_travail: | ||||
|             self.graphe[nom].ferme() | ||||
|  | ||||
|         for nom in self._contacts_double: | ||||
|             self.graphe[nom].active() | ||||
|  | ||||
|     def chute(self): | ||||
|         self.haut = False | ||||
|         for nom in self._contacts_repos: | ||||
|             self.graphe[nom].ferme() | ||||
|  | ||||
|         for nom in self._contacts_travail: | ||||
|             self.graphe[nom].ouvre() | ||||
|  | ||||
|         for nom in self._contacts_double: | ||||
|             self.graphe[nom].desactive() | ||||
|  | ||||
|     def update(self): | ||||
|         etat_precedent = self.haut | ||||
|         super().update() | ||||
|         if self.branche.i() >= self.SEUIL: | ||||
|             self.monte() | ||||
|         else: | ||||
|             self.chute() | ||||
|  | ||||
|         if self.est_point_arret and etat_precedent != self.haut: | ||||
|             self.graphe.flag_arret_simulation = True | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.haut | ||||
|  | ||||
|  | ||||
| class DemiRelaisBasculeur(Composant): | ||||
|     def __init__(self, conf, nom, graphe, cote): | ||||
|         super().__init__(conf, nom) | ||||
|         self.SEUIL = self.conf["SEUIL_RELAIS"] | ||||
|         self.r = self.conf["RES_RELAIS"] | ||||
|         self._contacts_basc = [] | ||||
|         self.haut = False | ||||
|         self.cote = cote | ||||
|         self.graphe = graphe | ||||
|  | ||||
|     def add_contact(self, nom): | ||||
|         self._contacts_basc.append(nom) | ||||
|  | ||||
|     def monte(self): | ||||
|         self.haut = True | ||||
|         if self.cote == Dir.GAUCHE: | ||||
|             for nom in self._contacts_basc: | ||||
|                 self.graphe.elements[nom].bascule_gauche() | ||||
|         elif self.cote == Dir.DROITE: | ||||
|             for nom in self._contacts_basc: | ||||
|                 self.graphe.elements[nom].bascule_droite() | ||||
|         else: | ||||
|             assert False | ||||
|  | ||||
|     def chute(self): | ||||
|         self.haut = False | ||||
|  | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         if self.branche.i() >= self.SEUIL: | ||||
|             self.monte() | ||||
|         else: | ||||
|             self.chute() | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.haut | ||||
|  | ||||
|  | ||||
| class Tempo(Composant): | ||||
|     """ | ||||
|     Tempo type "bilame piloté par le temps" | ||||
|     """ | ||||
|     def __init__(self, conf, nom, tempo_blocage, tempo_liberation): | ||||
|         super().__init__(conf, nom) | ||||
|         self.SEUIL = self.conf["SEUIL_TEMPO"] | ||||
|         self.h_trans = 0  # heure de la transition | ||||
|         self.h = 0  # heure courante | ||||
|         self.i_prec = 0.0  # intensité précédente | ||||
|         self.tempo_blocage = tempo_blocage / self.conf["DT"]  # durée de la tempo de blocage | ||||
|         self.tempo_liberation = tempo_liberation / self.conf["DT"]  # durée de la tempo de blocage | ||||
|         self.blocage = False | ||||
|         self.r = self.conf['RMIN'] | ||||
|  | ||||
|     def update(self): | ||||
|         if self.blocage: | ||||
|             if self.h - self.h_trans >= self.tempo_liberation: | ||||
|                 self.h_trans = self.h | ||||
|                 self.blocage = False | ||||
|                 self.r = self.conf["RMIN"] | ||||
|         else: | ||||
|             if self.branche.i() >= self.SEUIL: | ||||
|                 if self.i_prec < self.SEUIL: | ||||
|                     self.h_trans = self.h  # On mémorise l'heure de la transition | ||||
|  | ||||
|                 if self.h - self.h_trans >= self.tempo_blocage - 1: | ||||
|                     self.r = self.conf["RMAX"] | ||||
|                     self.blocage = True | ||||
|                     self.h_trans = self.h  # On mémorise l'heure à laquelle on bloque | ||||
|                 else: | ||||
|                     pass  # On est au-delà du seuil mais la tempo n'est pas échue | ||||
|         self.i_prec = self.branche.i() | ||||
|         self.h += 1 | ||||
|  | ||||
|     @property | ||||
|     def ouvert(self): | ||||
|         return self.blocage | ||||
|  | ||||
|     def etat(self): | ||||
|         return not self.blocage | ||||
|  | ||||
|  | ||||
| class Diode(Composant): | ||||
|     def __init__(self, conf, nom): | ||||
|         super().__init__(conf, nom) | ||||
|         self.r = self.conf["RMAX"] | ||||
|         self.reversed = False  # La diode est dans le sens opposé à la branche | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         self.r = self.conf["RMAX"] | ||||
|  | ||||
|     def passe_calcul(self): | ||||
|         if (not self.reversed and (self.branche.amont.u() > self.branche.aval.u())) \ | ||||
|                 or (self.reversed and (self.branche.amont.u() < self.branche.aval.u())): | ||||
|             self.r = self.conf["RMIN"] | ||||
|         else: | ||||
|             self.r = self.conf["RMAX"] | ||||
|  | ||||
|     def reverse(self): | ||||
|         self.reversed = True | ||||
|  | ||||
|     def etat(self): | ||||
|         return None | ||||
							
								
								
									
										29
									
								
								modele/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | ||||
| { | ||||
|     "circuit": { | ||||
|       "DT": 0.05, | ||||
|       "RMIN": 1E-32, | ||||
|       "RMAX": 1E32, | ||||
|       "UMAX": 24.5, | ||||
|       "USEUIL": 5, | ||||
|       "ISEUIL": 0.05, | ||||
|       "IMAX": 5.0, | ||||
|       "RES_DEFAULT": 100, | ||||
|       "RES_LAMPE": 100.0, | ||||
|       "SEUIL_LAMPE": 0.05, | ||||
|       "RES_RELAIS": 100.0, | ||||
|       "SEUIL_RELAIS": 0.05, | ||||
|       "SEUIL_TEMPO": 0.05, | ||||
|       "PULSE_PERIODE": 1.0, | ||||
|       "TOLERANCE_COURANT": 1e6 | ||||
|     }, | ||||
|     "ui": { | ||||
|       "DT": 0.13, | ||||
|       "BLOCK_H": 50, | ||||
|       "BLOCK_W": 40, | ||||
|       "RELAISBASC_WIDTH": 1.6, | ||||
|       "LINE_W": 1, | ||||
|       "WINDOW_W": 1100, | ||||
|       "WINDOW_H": 600 | ||||
|     } | ||||
|   } | ||||
|    | ||||
							
								
								
									
										356
									
								
								modele/donnees.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,356 @@ | ||||
| import logging | ||||
|  | ||||
|  | ||||
| class GraphStructException(Exception): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Noeud(object): | ||||
|     def __init__(self, donnees): | ||||
|         self.nom = donnees['nom'] | ||||
|         self.donnees = donnees | ||||
|         self.type = donnees['type'] | ||||
|         self.assoc_connecteurs = {} | ||||
|  | ||||
|     def __str__(self): | ||||
|         return f"<Noeud : {self.nom}, {self.type}>" | ||||
|  | ||||
|     def set_branche(self, direction, branche): | ||||
|         # Associe la branche correspondant à un connecteur | ||||
|         if direction in self.assoc_connecteurs: | ||||
|             self.assoc_connecteurs[direction].append(branche) | ||||
|         else: | ||||
|             self.assoc_connecteurs[direction] = [branche] | ||||
|  | ||||
|     def get_branches(self, direction): | ||||
|         return self.assoc_connecteurs[direction] | ||||
|  | ||||
|     def get_branche(self, direction): | ||||
|         c = self.get_branches(direction) | ||||
|         if len(c) == 1: | ||||
|             return c[0] | ||||
|         else: | ||||
|             raise GraphStructException("Invalid number of connectors") | ||||
|  | ||||
|     def remove_branche(self, branche, direction): | ||||
|         self.assoc_connecteurs[direction].remove(branche) | ||||
|  | ||||
|  | ||||
| class Arete(object): | ||||
|     def __init__(self, amont, amont_dir, aval, aval_dir): | ||||
|         self.amont = amont | ||||
|         self.amont_dir = amont_dir | ||||
|         self.aval = aval | ||||
|         self.aval_dir = aval_dir | ||||
|  | ||||
|     def deconnecte(self): | ||||
|         self.amont.remove_branche(self, self.amont_dir) | ||||
|         self.aval.remove_branche(self, self.aval_dir) | ||||
|         self.amont = None | ||||
|         self.aval = None | ||||
|         self.amont_dir = None | ||||
|         self.aval_dir = None | ||||
|  | ||||
|     def reconnecte_noeud(self, nsrc, ndir_src, ndest, ndir_dest): | ||||
|         """ | ||||
|         Déconnecte le noeud source, et le remplace par le noeud dest | ||||
|         """ | ||||
|         if nsrc == self.amont and self.amont_dir == ndir_src: | ||||
|             self.amont.remove_branche(self, self.amont_dir) | ||||
|             self.amont = ndest | ||||
|             self.amont_dir = ndir_dest | ||||
|             ndest.set_branche(ndir_dest,self) | ||||
|         elif nsrc == self.aval and self.aval_dir == ndir_src: | ||||
|             self.aval.remove_branche(self, self.aval_dir) | ||||
|             self.aval = ndest | ||||
|             self.aval_dir = ndir_dest | ||||
|             ndest.set_branche(ndir_dest,self) | ||||
|         else: | ||||
|             raise GraphStructException | ||||
|  | ||||
|     def get_neighbour(self, noeud, direction): | ||||
|         if self.amont == noeud and self.amont_dir == direction: | ||||
|             return self.aval, self.aval_dir | ||||
|         elif self.aval == noeud and self.aval_dir == direction: | ||||
|             return self.amont, self.amont_dir | ||||
|         else: | ||||
|             raise GraphStructException("No such neighbour") | ||||
|  | ||||
|     def get_amont(self): | ||||
|         return self.amont, self.amont_dir | ||||
|  | ||||
|     def get_aval (self): | ||||
|         return self.aval, self.aval_dir | ||||
|  | ||||
|  | ||||
| class Branche(Arete): | ||||
|     def __init__(self, amont, amont_dir, aval, aval_dir, composants=None): | ||||
|         super().__init__(amont, amont_dir, aval, aval_dir) | ||||
|         self.composants = [] if composants is None else composants | ||||
|  | ||||
|  | ||||
| class Condensateur(object): | ||||
|     """ | ||||
|     Un condensateur correspond en fait à l'objet connecteur câblé à deux noeuds amonts et aval | ||||
|     C'est donc "à la fois un noeud et deux branches" | ||||
|     """ | ||||
|     def __init__(self, donnees): | ||||
|         self.nom = donnees['nom'] | ||||
|         self.donnees = donnees | ||||
|         self.type = donnees['type'] | ||||
|         self.amont = None | ||||
|         self.aval = None | ||||
|         self.amont_dir = None  # le connecteur du noeud amont auquel on est raccordé | ||||
|         self.aval_dir = None  # le connecteur du noeud aval auquel on est raccordé | ||||
|  | ||||
|     def get_amont(self): | ||||
|         return self.amont, self.amont_dir | ||||
|  | ||||
|     def get_aval (self): | ||||
|         return self.aval, self.aval_dir | ||||
|  | ||||
|  | ||||
| class SchemaReader(object): | ||||
|     """ | ||||
|     A la lecture du graphe, tous les objets sont des noeuds et ils sont raccordés par des branches. | ||||
|     La simplification permet de supprimer les coudes. | ||||
|     La réduction des branches permet de transformer une série de branches et de composants en une seule branche | ||||
|     contentant les composants. | ||||
|     """ | ||||
|     REDUCTIBLE = ["ContactRepos", "Relais", "Tempo", "ContactTravail", "Bouton", "Resistance", | ||||
|                   "Diode", "Lampe", "RelaisCote", "Levier"] | ||||
|     RIEN_A_FAIRE = ["P24", "P0", "Pulse", "Noeud", "Condensateur", "ContactBasculeur", "ContactDouble"] | ||||
|     ID_NOM = -1 | ||||
|  | ||||
|     def __init__(self, d): | ||||
|         self.noeuds = {} | ||||
|         self.condensateurs = {} | ||||
|         self.branches = [] | ||||
|         self.composants = None | ||||
|         self.lire_donnees(d) | ||||
|  | ||||
|     @classmethod | ||||
|     def nouveau_nom(cls, prefix=""): | ||||
|         """ | ||||
|         Crée un nouveau nom | ||||
|         """ | ||||
|         cls.ID_NOM += 1 | ||||
|         return f"@{prefix}{cls.ID_NOM}" | ||||
|  | ||||
|     def connecte(self, n1, d1, n2, d2, composants=None): | ||||
|         """ | ||||
|         Crée une branche et connecte deux noeuds avec | ||||
|         """ | ||||
|         a = Branche(n1, d1, n2, d2, composants=composants) | ||||
|         self.branches.append(a) | ||||
|         n1.set_branche(d1, a) | ||||
|         n2.set_branche(d2, a) | ||||
|  | ||||
|     def connecte_condensateur_amont(self, cond, n1, d1): | ||||
|         cond.amont = n1 | ||||
|         cond.amont_dir = d1 | ||||
|  | ||||
|     def connecte_condensateur_aval(self, cond, n1, d1): | ||||
|         cond.aval = n1 | ||||
|         cond.aval_dir = d1 | ||||
|  | ||||
|     def remove_branche(self, branche): | ||||
|         self.branches.remove(branche) | ||||
|         branche.deconnecte() | ||||
|         return branche.composants | ||||
|  | ||||
|     def remove_noeud(self, noeud): | ||||
|         del self.noeuds[noeud] | ||||
|  | ||||
|     def lire_donnees(self, d): | ||||
|         """ | ||||
|         Lit le dictionnaire contenant le schéma | ||||
|         """ | ||||
|         # On commence par lire les noeuds | ||||
|         try: | ||||
|             for nom, donnees in d['blocs'].items(): | ||||
|                 donnees['nom'] = nom | ||||
|                 self.noeuds[nom] = Noeud(donnees) | ||||
|  | ||||
|             # On lit (et lie) ensuite les câbles | ||||
|             for amont, dir_amont, aval, dir_aval in d['cables']: | ||||
|                 self.connecte(self.noeuds[amont], dir_amont, self.noeuds[aval], dir_aval) | ||||
|         except KeyError: | ||||
|             raise GraphStructException | ||||
|  | ||||
|     def traiter_composites(self): | ||||
|         """ | ||||
|         Traite les noeuds composites (contacts doubles, relais basculeurs, etc.) et les transforme en objets simples. | ||||
|         """ | ||||
|         noeuds_a_supprimer = [] | ||||
|         noeuds_a_ajouter = [] | ||||
|  | ||||
|         for nom, noeud in self.noeuds.items(): | ||||
|             # Parcoure les noeuds en cherchant les noeuds composites | ||||
|  | ||||
|             if noeud.type == "RelaisCote": | ||||
|                 # On transforme en relais simple | ||||
|                 noeud.type = "Relais" | ||||
|  | ||||
|                 if 'orientation' not in noeud.donnees or noeud.donnees['orientation'] == 0: | ||||
|                     b_hg = noeud.get_branche("hg") | ||||
|                     b_bg = noeud.get_branche("bg") | ||||
|                     b_hg.reconnecte_noeud(noeud, "hg", noeud, "g") | ||||
|                     b_bg.reconnecte_noeud(noeud, "bg", noeud, "d") | ||||
|                 elif noeud.donnees['orientation'] == 180: | ||||
|                     b_hd = noeud.get_branche("hd") | ||||
|                     b_bd = noeud.get_branche("bd") | ||||
|                     b_hd.reconnecte_noeud(noeud, "hd", noeud, "g") | ||||
|                     b_bd.reconnecte_noeud(noeud, "bd", noeud, "d") | ||||
|                 else: | ||||
|                     assert False, "Rien à faire là" | ||||
|  | ||||
|             elif noeud.type == "RelaisBasculeur": | ||||
|                 noeuds_a_supprimer.append(nom) | ||||
|                 rel_g = Noeud({'nom': noeud.nom + ".gauche", 'type': 'Relais', | ||||
|                                'orientation': noeud.donnees['orientation'], 'basculeur': 'gauche'}) | ||||
|                 rel_d = Noeud({'nom': noeud.nom + ".droite", 'type': 'Relais', | ||||
|                                'orientation': noeud.donnees['orientation'], 'basculeur': 'droite'}) | ||||
|  | ||||
|                 noeuds_a_ajouter.append((noeud.nom + ".gauche", rel_g)) | ||||
|                 noeuds_a_ajouter.append((noeud.nom + ".droite", rel_d)) | ||||
|  | ||||
|                 # On récupère les branches | ||||
|                 br_hg = noeud.get_branche("hg") | ||||
|                 br_bg = noeud.get_branche("bg") | ||||
|                 br_hd = noeud.get_branche("hd") | ||||
|                 br_bd = noeud.get_branche("bd") | ||||
|  | ||||
|                 # Puis les voisins | ||||
|                 vois_hg, vois_hg_dir = br_hg.get_neighbour(noeud, "hg") | ||||
|                 vois_bg, vois_bg_dir = br_bg.get_neighbour(noeud, "bg") | ||||
|                 vois_hd, vois_hd_dir = br_hd.get_neighbour(noeud, "hd") | ||||
|                 vois_bd, vois_bd_dir = br_bd.get_neighbour(noeud, "bd") | ||||
|  | ||||
|                 # On supprime les branches | ||||
|                 cmp_hg = self.remove_branche(br_hg) | ||||
|                 cmp_bg = self.remove_branche(br_bg) | ||||
|                 cmp_hd = self.remove_branche(br_hd) | ||||
|                 cmp_bd = self.remove_branche(br_bd) | ||||
|  | ||||
|                 # On lie les nouveaux noeuds | ||||
|                 self.connecte(rel_g, "g", vois_hg, vois_hg_dir, cmp_hg) | ||||
|                 self.connecte(rel_g, "d", vois_bg, vois_bg_dir, cmp_bg) | ||||
|                 self.connecte(rel_d, "g", vois_hd, vois_hd_dir, cmp_hd) | ||||
|                 self.connecte(rel_d, "d", vois_bd, vois_bd_dir, cmp_bd) | ||||
|  | ||||
|         [self.remove_noeud(n) for n in noeuds_a_supprimer] | ||||
|         [self.noeuds.__setitem__(nom, valeur) for nom, valeur in noeuds_a_ajouter] | ||||
|  | ||||
|     def simplifier(self): | ||||
|         """ | ||||
|         Simplifie le graphe : | ||||
|         - supprime les coudes | ||||
|         """ | ||||
|         # Supprime les coudes | ||||
|         coudes = [] | ||||
|         for n in self.noeuds.values(): | ||||
|             if n.type == 'Coude': | ||||
|                 try: | ||||
|                     a1, a2 = n.get_branches("m") | ||||
|                 except ValueError: | ||||
|                     raise GraphStructException("Un coude doit avoir deux voisins") | ||||
|  | ||||
|                 # On récupère les voisins | ||||
|                 v1, d1 = a1.get_neighbour(n, "m") | ||||
|                 v2, d2 = a2.get_neighbour(n, "m") | ||||
|  | ||||
|                 comp1 = self.remove_branche(a1) | ||||
|                 comp2 = self.remove_branche(a2) | ||||
|  | ||||
|                 self.connecte(v1, d1, v2, d2, comp1 + comp2) | ||||
|                 coudes.append(n) | ||||
|  | ||||
|         [self.remove_noeud(n.nom) for n in coudes] | ||||
|  | ||||
|     def traiter_condensateurs(self): | ||||
|         cond_list = [] | ||||
|         for nom, noeud in self.noeuds.items(): | ||||
|             if noeud.type == "Condensateur": | ||||
|                 branche_g = noeud.get_branche("g") | ||||
|                 branche_d = noeud.get_branche("d") | ||||
|                 n1 = self.nouveau_nom() | ||||
|                 nn_amont = Noeud({'nom': n1, 'type': 'Noeud'}) | ||||
|                 cond_list.append(nn_amont) | ||||
|                 n2 = self.nouveau_nom() | ||||
|                 nn_aval = Noeud({'nom': n2, 'type': 'Noeud'}) | ||||
|                 cond_list.append(nn_aval) | ||||
|  | ||||
|                 cond = Condensateur(noeud.donnees) | ||||
|                 self.condensateurs[nom] = cond | ||||
|                 cond.amont = nn_amont | ||||
|                 cond.aval = nn_aval | ||||
|                 # On raccorde le nouveau noeud amont au voisin amont initial | ||||
|                 voisin_g, dir_g = branche_g.get_neighbour(noeud, "g") | ||||
|                 composants_g = self.remove_branche(branche_g) | ||||
|                 self.connecte(voisin_g, dir_g, nn_amont, "m", composants_g) | ||||
|  | ||||
|                 # Le noeud nouveau noeud amont au condensateur | ||||
|                 self.connecte_condensateur_amont(cond, nn_amont, "m") | ||||
|  | ||||
|                 # Le nouveau noeud aval au condensateur | ||||
|                 self.connecte_condensateur_aval(cond, nn_aval, "m") | ||||
|  | ||||
|                 # On raccorde le nouveau noeud aval à la branche aval initiale | ||||
|                 voisin_d, dir_d = branche_d.get_neighbour(noeud, "d") | ||||
|                 composants_d = self.remove_branche(branche_d) | ||||
|                 self.connecte(voisin_d, dir_d, nn_aval, "m", composants_d) | ||||
|  | ||||
|         for c in cond_list: | ||||
|             self.noeuds[c.nom] = c | ||||
|  | ||||
|     def reduire_branches(self): | ||||
|         noeuds_a_supprimer = [] | ||||
|         for nom, noeud in self.noeuds.items(): | ||||
|             if noeud.type in self.REDUCTIBLE: | ||||
|                 # Le composant est stockable dans la branche (composant simple en série) | ||||
|                 b_gauche = noeud.get_branche("g") | ||||
|                 b_droite = noeud.get_branche("d") | ||||
|  | ||||
|                 voisin_g, voisin_g_dir = b_gauche.get_neighbour(noeud, "g") | ||||
|                 voisin_d, voisin_d_dir = b_droite.get_neighbour(noeud, "d") | ||||
|  | ||||
|                 comp_br_gauche = self.remove_branche(b_gauche) | ||||
|                 comp_br_droite = self.remove_branche(b_droite) | ||||
|  | ||||
|                 self.connecte(voisin_g, voisin_g_dir, voisin_d, voisin_d_dir, comp_br_gauche + [noeud] + comp_br_droite) | ||||
|  | ||||
|                 noeuds_a_supprimer.append(nom) | ||||
|  | ||||
|                 if noeud.type == "Diode" and noeud.donnees['orientation'] == 180: | ||||
|                     noeud.nom = "!" + noeud.nom | ||||
|  | ||||
|             elif noeud.type == "Coude": | ||||
|                 assert False, "Les coudes auraient dûs être éliminés !" | ||||
|             elif noeud.type in self.RIEN_A_FAIRE: | ||||
|                 pass | ||||
|             else: | ||||
|                 raise GraphStructException("Type inconnu : " + noeud.type) | ||||
|  | ||||
|         for n in noeuds_a_supprimer: | ||||
|             del self.noeuds[n] | ||||
|  | ||||
|     def make_liste_composants(self): | ||||
|         self.composants = {} | ||||
|         for b in self.branches: | ||||
|             for c in b.composants: | ||||
|                 self.composants[c.nom] = c | ||||
|  | ||||
|     def process(self): | ||||
|         """ | ||||
|         Méthode principale de traitement du graphe | ||||
|         """ | ||||
|         try: | ||||
|             self.simplifier() | ||||
|             self.traiter_composites() | ||||
|             self.traiter_condensateurs() | ||||
|             self.reduire_branches() | ||||
|             self.make_liste_composants() | ||||
|         except KeyError: | ||||
|             logging.exception("Erreur de chaînage dans le graphe") | ||||
|             raise GraphStructException | ||||
							
								
								
									
										534
									
								
								modele/elements.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,534 @@ | ||||
| from modele.exceptions import (WrongElecPropertyException, SurtensionException, | ||||
|                          SurintensiteException, Dir) | ||||
|  | ||||
|  | ||||
| class Element(object): | ||||
|     """ | ||||
|     Classe mère. | ||||
|     Le graphe lui-même est composé de Potentiels fixes (Potentiel), de Noeuds, et de Branches. | ||||
|     Les branches contiennent une liste de composants en série. | ||||
|  | ||||
|     Les éléments doivent implémenter quatre méthodes pour le calcul des valeurs : | ||||
|     init_cycle est appelée avant chaque cycle, avant l'initialisation de la matrice | ||||
|     report_pass_1 est appelée après la première passe pour report des valeurs de la matrice (et avant la construction | ||||
|     de la matrice de la deuxième passe) | ||||
|     report_pass2 est appelée après la 2e passe pour reporter les valeurs finales calculées | ||||
|     update est appelée après le report de la 2e passe, pour pouvoir faire la mise à jour des états des éléments | ||||
|  | ||||
|     """ | ||||
|     P_CST, P_NOEUD, P_DLT, P_COND, P_EQVAR, P_BSCLAME = range(6) | ||||
|  | ||||
|     def __init__(self, conf, nom, type_potentiel): | ||||
|         self.type_potentiel = type_potentiel | ||||
|         self.conf = conf | ||||
|         self.nom = nom | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         pass | ||||
|  | ||||
|     def passe_calcul(self, solutions, index): | ||||
|         pass | ||||
|  | ||||
|     def update(self): | ||||
|         pass | ||||
|  | ||||
|     def etat(self): | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def coherence(self): | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def eq_elts(self): | ||||
|         """ | ||||
|         Retourne les équipotentiels | ||||
|         Par défaut, un seul équipotentiel | ||||
|         """ | ||||
|         return [self] | ||||
|  | ||||
|     def get_potentiel(self, direction): | ||||
|         """ | ||||
|         Par défaut, un seul potentiel quel que soit la direction | ||||
|         """ | ||||
|         return self | ||||
|  | ||||
|  | ||||
| class Potentiel(Element): | ||||
|     """ | ||||
|     Potentiel à 24V ou à 0V | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, conf, nom, u=0.0, voisins=None): | ||||
|         super().__init__(conf, nom, self.P_CST) | ||||
|         self._u = u | ||||
|         if voisins is None: | ||||
|             voisins = [] | ||||
|         self._voisins = voisins | ||||
|  | ||||
|     def add_voisins(self, voisins): | ||||
|         self._voisins += voisins | ||||
|  | ||||
|     def voisins(self): | ||||
|         return self._voisins | ||||
|  | ||||
|     def u(self): | ||||
|         return self._u | ||||
|  | ||||
|     def i(self): | ||||
|         raise WrongElecPropertyException | ||||
|  | ||||
|     def coherence(self): | ||||
|         pass | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.u() >= self.conf['USEUIL'] | ||||
|  | ||||
| class PotPulse(Potentiel): | ||||
|     def __init__(self, conf, nom, u=0.0, periode=None, voisins=None): | ||||
|         super().__init__(conf, nom, u, voisins) | ||||
|         if periode is None: | ||||
|             periode = self.conf['PULSE_PERIODE'] | ||||
|         self.periode = periode / self.conf['DT'] | ||||
|         self.u_max = u | ||||
|         self.actif = True | ||||
|         self.compteur = 0 | ||||
|  | ||||
|     def update(self): | ||||
|         self.compteur += 1 | ||||
|         if self.actif: | ||||
|             if self.compteur >= self.periode: | ||||
|                 self.compteur = 0 | ||||
|                 self._u = 0. | ||||
|                 self.actif = False | ||||
|         else: | ||||
|             if self.compteur >= self.periode: | ||||
|                 self.compteur = 0 | ||||
|                 self._u = self.u_max | ||||
|                 self.actif = True | ||||
|  | ||||
|  | ||||
| class Noeud(Element): | ||||
|     """ | ||||
|     Nœud du graphe | ||||
|  | ||||
|     self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches | ||||
|     """ | ||||
|     def __init__(self, conf, nom, voisins=None): | ||||
|         super().__init__(conf, nom, self.P_NOEUD) | ||||
|         self._u = None | ||||
|         if voisins is None: | ||||
|             voisins = [] | ||||
|         self._voisins = voisins | ||||
|  | ||||
|     def add_voisins(self, voisins): | ||||
|         self._voisins += voisins | ||||
|  | ||||
|     def voisins(self): | ||||
|         return self._voisins | ||||
|  | ||||
|     def passe_calcul(self, vect, index): | ||||
|         super().passe_calcul(vect, index) | ||||
|         self._u = vect[index] | ||||
|  | ||||
|     def u(self): | ||||
|         return self._u | ||||
|  | ||||
|     def coherence(self): | ||||
|         if abs(self.u()) >= self.conf['UMAX']: | ||||
|             raise SurtensionException | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.u() >= self.conf['USEUIL'] | ||||
|      | ||||
|  | ||||
|  | ||||
|     def verifier_loi_des_noeuds(self): | ||||
|  | ||||
|         """Dans cette méthode, self._voisins contient les branches connectées au nœud, et polarite indique si le courant est entrant (-1) ou sortant (+1).  | ||||
|         La variable courant_total accumule la somme des courants, et self.conf['TOLERANCE_COURANT'] est une petite valeur seuil pour tolérer des imprécisions | ||||
|           numériques (par exemple, 1e-6).""" | ||||
|          | ||||
|         courant_total = 0 | ||||
|         for voisin, polarite, _ in self._voisins: | ||||
|             if polarite == -1: | ||||
|                 courant_total -= voisin.i() | ||||
|             else: | ||||
|                 courant_total += voisin.i() | ||||
|  | ||||
|         if abs(courant_total) > self.conf['TOLERANCE_COURANT']: | ||||
|             raise Exception(f"La loi des nœuds n'est pas respectée pour le noeud {self.nom}. Total courant: {courant_total}") | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| class Branche(Element): | ||||
|     """ | ||||
|     Branche du graphe. | ||||
|     La branche contient un certain nombre de composants en série, qui peuvent être des relais, tempos, résistances | ||||
|     ou contacts (équation). N'est pas utilisable pour les condensateurs. | ||||
|     """ | ||||
|     def __init__(self, conf, nom, composants): | ||||
|         super().__init__(conf, nom, self.P_DLT) | ||||
|         self.composants = composants | ||||
|         self.amont = None | ||||
|         self.aval = None | ||||
|         self._i = 0.0 | ||||
|  | ||||
|     def add_voisins(self, amont, aval): | ||||
|         self.amont = amont | ||||
|         self.aval = aval | ||||
|  | ||||
|     def r(self): | ||||
|         return sum([x.r for x in self.composants]) + self.conf['RMIN'] | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         super().init_cycle() | ||||
|         [x.init_cycle() for x in self.composants] | ||||
|  | ||||
|     def passe_calcul(self, vect, index): | ||||
|         super().passe_calcul(vect, index) | ||||
|         self._i = vect[index]  # Important de mettre à jour i avant de mettre à jour les composants | ||||
|         [x.passe_calcul() for x in self.composants] | ||||
|  | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         [x.update() for x in self.composants] | ||||
|  | ||||
|     def i(self): | ||||
|         return self._i | ||||
|  | ||||
|     def coherence(self): | ||||
|         if abs(self.i()) >= self.conf['IMAX']: | ||||
|             raise SurintensiteException(f"Dans la branche {self.nom}") | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.i() >= self.conf['ISEUIL'] | ||||
|  | ||||
|  | ||||
| class Condensateur(Element): | ||||
|     """ | ||||
|     Condensateur. | ||||
|  | ||||
|     La seule truande est que la tension au borne est en réalité calculée avec la charge du cycle précédent. | ||||
|     """ | ||||
|     def __init__(self, conf, nom, capacite, coef_mul_tension): | ||||
|         super().__init__(conf, nom, self.P_COND) | ||||
|         self.capacite = capacite | ||||
|         self.amont = None | ||||
|         self.aval = None | ||||
|         self._i = 0.0 | ||||
|         self.q = 0.0 | ||||
|         self.q_prec = 0.0 | ||||
|         self.coef_mul_tension = coef_mul_tension | ||||
|  | ||||
|     def add_voisins(self, amont, aval): | ||||
|         self.amont = amont | ||||
|         self.aval = aval | ||||
|  | ||||
|     def r(self): | ||||
|         raise WrongElecPropertyException | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         super().init_cycle() | ||||
|  | ||||
|     def passe_calcul(self, vect, index): | ||||
|         super().passe_calcul(vect, index) | ||||
|         self._i = vect[index]  # Important de mettre à jour i avant de mettre à jour les composants | ||||
|  | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         self.q_prec = self.q | ||||
|         q = self.q + self.i() * self.conf['DT'] | ||||
|         self.q = q | ||||
|  | ||||
|     def i(self): | ||||
|         return self._i | ||||
|  | ||||
|     def coherence(self): | ||||
|         if abs(self.i()) >= self.conf['IMAX']: | ||||
|             raise SurintensiteException | ||||
|  | ||||
|     def etat(self): | ||||
|         return bool(self.i() >= self.conf['ISEUIL']) | ||||
|  | ||||
|  | ||||
| class ContactBasculeur(Noeud): | ||||
|     """ | ||||
|     Nœud du graphe | ||||
|  | ||||
|     self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches | ||||
|     """ | ||||
|     UMAX = 24.5 | ||||
|  | ||||
|     class PotentielLocal(Element): | ||||
|         def __init__(self, conf, nom, voisins=None): | ||||
|             self.lame = None | ||||
|             super().__init__(conf, nom, self.P_NOEUD) | ||||
|             self._u = None | ||||
|             if voisins is None: | ||||
|                 voisins = [] | ||||
|             self._voisins = voisins | ||||
|             self.etat = False | ||||
|  | ||||
|         def set_lame(self, lame): | ||||
|             self.lame = lame | ||||
|  | ||||
|         def add_voisins(self, voisins): | ||||
|             self._voisins += voisins | ||||
|  | ||||
|         def set_etat(self, etat): | ||||
|             self.etat = etat | ||||
|  | ||||
|         def voisins(self): | ||||
|             return self._voisins + ([(self.lame, +1, "foo")] if self.etat else []) | ||||
|  | ||||
|         def passe_calcul(self, vect, index): | ||||
|             super().passe_calcul(vect, index) | ||||
|             self._u = vect[index] | ||||
|  | ||||
|         def u(self): | ||||
|             return self._u | ||||
|  | ||||
|         def coherence(self): | ||||
|             if abs(self.u()) >= self.conf['UMAX']: | ||||
|                 raise SurtensionException | ||||
|  | ||||
|     class Lame(Element): | ||||
|         def __init__(self, conf, nom, contact, gauche, droite): | ||||
|             self.amont = contact | ||||
|             self.aval = None | ||||
|             self.gauche = gauche | ||||
|             self.droite = droite | ||||
|             self.position = None | ||||
|             super().__init__(conf, nom, self.P_DLT) | ||||
|             self._i = None | ||||
|  | ||||
|         def bascule(self, position): | ||||
|             self.position = position | ||||
|             if position == Dir.GAUCHE: | ||||
|                 self.aval = self.gauche | ||||
|             else: | ||||
|                 self.aval = self.droite | ||||
|  | ||||
|         def i(self): | ||||
|             return self._i | ||||
|  | ||||
|         def r(self): | ||||
|             return self.conf['RMIN'] | ||||
|  | ||||
|     # Classe principale | ||||
|     def __init__(self, conf, nom, graphe, voisins=None): | ||||
|         self.graphe = graphe | ||||
|         self.position = None | ||||
|         self.potentiel_gauche = self.PotentielLocal(conf, nom + ".G") | ||||
|         self.potentiel_droit = self.PotentielLocal(conf, nom + ".D") | ||||
|         self.lame = self.Lame(conf, nom + ".L", self, self.potentiel_gauche, self.potentiel_droit) | ||||
|         self.potentiel_gauche.set_lame(self.lame) | ||||
|         self.potentiel_droit.set_lame(self.lame) | ||||
|         self._voisins = [(self.lame, -1, "foo")] + voisins if voisins is not None else [] | ||||
|         super().__init__(conf, nom, self.P_NOEUD) | ||||
|         self.bascule_gauche() | ||||
|  | ||||
|     def eq_elts(self): | ||||
|         return [self, self.potentiel_gauche, self.potentiel_droit, self.lame] | ||||
|  | ||||
|     def add_voisins(self, voisins): | ||||
|         for vois_tuple in voisins: | ||||
|             _, _, connecteur = vois_tuple | ||||
|             if connecteur == 'b': | ||||
|                 self._voisins = [vois_tuple] | ||||
|             else: | ||||
|                 # Les autres connecteurs doivent être câblés vers les ConnecteursLocaux | ||||
|                 raise "Invalid connector for RelaisBasculeur" | ||||
|  | ||||
|     def voisins(self): | ||||
|         return self._voisins | ||||
|  | ||||
|     def bascule_gauche(self): | ||||
|         self.position = Dir.GAUCHE | ||||
|         self.lame.bascule(self.position) | ||||
|         self.potentiel_gauche.set_etat(True) | ||||
|         self.potentiel_droit.set_etat(False) | ||||
|  | ||||
|     def bascule_droite(self): | ||||
|         self.position = Dir.DROITE | ||||
|         self.lame.bascule(self.position) | ||||
|         self.potentiel_gauche.set_etat(False) | ||||
|         self.potentiel_droit.set_etat(True) | ||||
|  | ||||
|     def get_potentiel(self, direction): | ||||
|         """ | ||||
|         Par défaut, un seul potentiel quel que soit la direction | ||||
|         """ | ||||
|         if direction == "b": | ||||
|             return self | ||||
|         elif direction == "g": | ||||
|             return self.potentiel_gauche | ||||
|         elif direction == "d": | ||||
|             return self.potentiel_droit | ||||
|         else: | ||||
|             assert False | ||||
|  | ||||
|     def passe_calcul(self, vect, index): | ||||
|         super().passe_calcul(vect, index) | ||||
|         self.potentiel_droit.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_droit)) | ||||
|         self.potentiel_gauche.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_gauche)) | ||||
|         self._u = vect[index] | ||||
|  | ||||
|     def u(self): | ||||
|         return self._u | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.lame.position | ||||
|  | ||||
|     def coherence(self): | ||||
|         if abs(self.u()) >= self.conf['UMAX']: | ||||
|             raise SurtensionException | ||||
|         self.potentiel_droit.coherence() | ||||
|         self.potentiel_gauche.coherence() | ||||
|  | ||||
|  | ||||
| class ContactDouble(Noeud): | ||||
|     """ | ||||
|     Nœud du graphe | ||||
|  | ||||
|     self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches | ||||
|     """ | ||||
|     UMAX = 24.5 | ||||
|  | ||||
|     class PotentielLocal(Element): | ||||
|         def __init__(self, conf, nom, voisins=None): | ||||
|             self.lame = None | ||||
|             super().__init__(conf, nom, self.P_NOEUD) | ||||
|             self._u = None | ||||
|             if voisins is None: | ||||
|                 voisins = [] | ||||
|             self._voisins = voisins | ||||
|             self.etat = False | ||||
|  | ||||
|         def set_lame(self, lame): | ||||
|             self.lame = lame | ||||
|  | ||||
|         def add_voisins(self, voisins): | ||||
|             self._voisins += voisins | ||||
|  | ||||
|         def set_etat(self, etat): | ||||
|             self.etat = etat | ||||
|  | ||||
|         def voisins(self): | ||||
|             return self._voisins + ([(self.lame, +1, "foo")] if self.etat else []) | ||||
|  | ||||
|         def passe_calcul(self, vect, index): | ||||
|             super().passe_calcul(vect, index) | ||||
|             self._u = vect[index] | ||||
|  | ||||
|         def u(self): | ||||
|             return self._u | ||||
|  | ||||
|         def coherence(self): | ||||
|             if abs(self.u()) >= self.conf['UMAX']: | ||||
|                 raise SurtensionException | ||||
|  | ||||
|     class Lame(Element): | ||||
|         def __init__(self, conf, nom, contact, gauche, droite): | ||||
|             self.amont = contact | ||||
|             self.aval = None | ||||
|             self.repos = gauche | ||||
|             self.travail = droite | ||||
|             self.position = False  # Travail = True | ||||
|             super().__init__(conf, nom, self.P_DLT) | ||||
|             self._i = None | ||||
|  | ||||
|         def set_position(self, position): | ||||
|             self.position = position | ||||
|             if position: | ||||
|                 self.aval = self.travail | ||||
|             else: | ||||
|                 self.aval = self.repos | ||||
|  | ||||
|         def i(self): | ||||
|             return self._i | ||||
|  | ||||
|         def r(self): | ||||
|             return self.conf['RMIN'] | ||||
|  | ||||
|     # Classe principale | ||||
|     def __init__(self, conf, nom, graphe, voisins=None, orientation=0): | ||||
|         self.graphe = graphe | ||||
|         self.orientation = orientation | ||||
|         self.potentiel_repos = self.PotentielLocal(conf, nom + ".repos") | ||||
|         self.potentiel_travail = self.PotentielLocal(conf, nom + ".travail") | ||||
|         self.lame = self.Lame(conf, nom + ".L", self, self.potentiel_repos, self.potentiel_travail) | ||||
|         self.potentiel_repos.set_lame(self.lame) | ||||
|         self.potentiel_travail.set_lame(self.lame) | ||||
|         self._voisins = [(self.lame, -1, "foo")] + voisins if voisins is not None else [] | ||||
|         super().__init__(conf, nom, self.P_NOEUD) | ||||
|         self.lame.set_position(False) | ||||
|  | ||||
|     def eq_elts(self): | ||||
|         return [self, self.potentiel_repos, self.potentiel_travail, self.lame] | ||||
|  | ||||
|     def add_voisins(self, voisins): | ||||
|         for vois_tuple in voisins: | ||||
|             _, _, connecteur = vois_tuple | ||||
|             if (self.orientation == 0 and connecteur == 'd') \ | ||||
|                     or (self.orientation == 180 and connecteur == 'g'): | ||||
|                 self._voisins = [vois_tuple] | ||||
|             else: | ||||
|                 # Les autres connecteurs doivent être câblés vers les ConnecteursLocaux | ||||
|                 raise "Invalid connector for ContactDouble" | ||||
|  | ||||
|     def voisins(self): | ||||
|         return self._voisins | ||||
|  | ||||
|     def get_potentiel(self, direction): | ||||
|         """ | ||||
|         Par défaut, un seul potentiel quel que soit la direction | ||||
|         """ | ||||
|         if self.orientation == 0: | ||||
|             if direction == "d": | ||||
|                 return self | ||||
|             elif direction == "bg": | ||||
|                 return self.potentiel_repos | ||||
|             elif direction == "hg": | ||||
|                 return self.potentiel_travail | ||||
|             else: | ||||
|                 assert False | ||||
|         elif self.orientation == 180: | ||||
|             if direction == "g": | ||||
|                 return self | ||||
|             elif direction == "bd": | ||||
|                 return self.potentiel_repos | ||||
|             elif direction == "hd": | ||||
|                 return self.potentiel_travail | ||||
|             else: | ||||
|                 assert False | ||||
|         else: | ||||
|             assert False | ||||
|  | ||||
|     def passe_calcul(self, vect, index): | ||||
|         super().passe_calcul(vect, index) | ||||
|         self.potentiel_travail.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_travail)) | ||||
|         self.potentiel_repos.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_repos)) | ||||
|         self._u = vect[index] | ||||
|  | ||||
|     def u(self): | ||||
|         return self._u | ||||
|  | ||||
|     def etat(self): | ||||
|         return self.lame.position | ||||
|  | ||||
|     def coherence(self): | ||||
|         if abs(self.u()) >= self.conf['UMAX']: | ||||
|             raise SurtensionException | ||||
|         self.potentiel_travail.coherence() | ||||
|         self.potentiel_repos.coherence() | ||||
|  | ||||
|     def active(self): | ||||
|         self.lame.set_position(True) | ||||
|         self.potentiel_travail.set_etat(True) | ||||
|         self.potentiel_repos.set_etat(False) | ||||
|  | ||||
|     def desactive(self): | ||||
|         self.lame.set_position(False) | ||||
|         self.potentiel_travail.set_etat(False) | ||||
|         self.potentiel_repos.set_etat(True) | ||||
							
								
								
									
										22
									
								
								modele/exceptions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| from enum import IntEnum | ||||
|  | ||||
|  | ||||
| class WrongElecPropertyException(Exception): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class NonPolariseException(Exception): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class SurtensionException(Exception): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class SurintensiteException(Exception): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Dir(IntEnum): | ||||
|     GAUCHE = 1 | ||||
|     DROITE = 2 | ||||
							
								
								
									
										172
									
								
								modele/graphe.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,172 @@ | ||||
| import modele.composants as mc | ||||
| import modele.elements as me | ||||
| from modele.exceptions import Dir | ||||
| from modele.donnees import GraphStructException | ||||
|  | ||||
|  | ||||
| class Vecteur(object): | ||||
|     """ | ||||
|     Associe les éléments du graphe à leur rang dans le vecteur correspondant aux rangs dans la matrice. | ||||
|     """ | ||||
|     def __init__(self, elements): | ||||
|         self._liste = [eq_elt for element in elements.values() for eq_elt in element.eq_elts()] | ||||
|  | ||||
|         self._index = {}  # Associe à un élément son index dans la matrice | ||||
|         for index, element in enumerate(self._liste): | ||||
|             self._index[element] = index | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self._liste) | ||||
|  | ||||
|     def index(self, element): | ||||
|         return self._index[element] | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return self._liste.__iter__() | ||||
|  | ||||
|  | ||||
| class Graphe(object): | ||||
|     ID_BR = -1 | ||||
|  | ||||
|     @classmethod | ||||
|     def branch_id(cls): | ||||
|         cls.ID_BR += 1 | ||||
|         return f"b{cls.ID_BR}" | ||||
|  | ||||
|     def __init__(self, conf): | ||||
|         self.conf = conf | ||||
|         self.elements = None | ||||
|         self.composants = None | ||||
|         self.vecteur = None | ||||
|         self.flag_arret_simulation = False  | ||||
|  | ||||
|     def load_data_from_schema_reader(self, reader): | ||||
|         self.elements = {} | ||||
|         self.composants = {} | ||||
|  | ||||
|         # Construction des éléments et composants | ||||
|         for nom, valeur in reader.composants.items(): | ||||
|             if valeur.type == 'Bouton' or valeur.type == 'ContactTravail' or valeur.type == 'ContactRepos' \ | ||||
|                     or valeur.type == 'Levier': | ||||
|                 self.composants[nom] = mc.Contact(self.conf, nom, valeur.type) | ||||
|             elif valeur.type == 'Relais': | ||||
|                 if valeur.donnees.get('basculeur') == 'gauche': | ||||
|                     self.composants[nom] = mc.DemiRelaisBasculeur(self.conf, nom, self, Dir.GAUCHE) | ||||
|                 elif valeur.donnees.get('basculeur') == 'droite': | ||||
|                     self.composants[nom] = mc.DemiRelaisBasculeur(self.conf, nom, self, Dir.DROITE) | ||||
|                 else: | ||||
|                     self.composants[nom] = mc.Relais(self.conf, nom, self) | ||||
|             elif valeur.type == 'Tempo': | ||||
|                 self.composants[nom] = mc.Tempo(self.conf, nom, valeur.donnees['tempo_blocage'], | ||||
|                                                 valeur.donnees['tempo_liberation']) | ||||
|             elif valeur.type == 'Resistance': | ||||
|                 if 'valeur' not in valeur.donnees: | ||||
|                     v = None | ||||
|                 else: | ||||
|                     v = valeur.donnees['valeur'] | ||||
|                 self.composants[nom] = mc.Resistance(self.conf, nom, v) | ||||
|                 del v | ||||
|             elif valeur.type == 'Lampe': | ||||
|                 self.composants[nom] = mc.Lampe(self.conf, nom) | ||||
|             elif valeur.type == 'Diode': | ||||
|                 d = mc.Diode(self.conf, nom) | ||||
|                 self.composants[nom] = d | ||||
|                 self.composants["!" + nom] = d | ||||
|                 del d | ||||
|  | ||||
|         for nom, valeur in reader.noeuds.items(): | ||||
|             if valeur.type == "Noeud": | ||||
|                 self.elements[nom] = me.Noeud(self.conf, nom) | ||||
|             elif valeur.type == "P24": | ||||
|                 self.elements[nom] = me.Potentiel(self.conf, nom, 24.) | ||||
|             elif valeur.type == "P0": | ||||
|                 self.elements[nom] = me.Potentiel(self.conf, nom, 0.) | ||||
|             elif valeur.type == "Pulse": | ||||
|                 if "periode" not in valeur.donnees: | ||||
|                     p = None | ||||
|                 else: | ||||
|                     p = valeur.donnees["periode"] | ||||
|                 self.elements[nom] = me.PotPulse(self.conf, nom, 24., p) | ||||
|             elif valeur.type == "ContactBasculeur": | ||||
|                 self.elements[nom] = me.ContactBasculeur(self.conf, nom, self) | ||||
|             elif valeur.type == "ContactDouble": | ||||
|                 self.elements[nom] = me.ContactDouble(self.conf, nom, self, orientation=valeur.donnees['orientation']) | ||||
|  | ||||
|         for nom, valeur in reader.condensateurs.items(): | ||||
|             cnd = me.Condensateur(self.conf, nom, valeur.donnees['capacite'], valeur.donnees['coef_mul_tension']) | ||||
|  | ||||
|             v_amont_schm, v_amont_dir = valeur.get_amont() | ||||
|             v_aval_schm, v_aval_dir = valeur.get_aval() | ||||
|  | ||||
|             v_amont = self.elements[v_amont_schm.nom] | ||||
|             v_aval = self.elements[v_aval_schm.nom] | ||||
|  | ||||
|             cnd.add_voisins(v_amont, v_aval) | ||||
|             v_amont.add_voisins([(cnd, -1, v_amont_dir)]) | ||||
|             v_aval.add_voisins([(cnd, +1, v_aval_dir)]) | ||||
|             self.elements[nom] = cnd | ||||
|             del cnd | ||||
|  | ||||
|         # Ajout des liens entre relais et contacts | ||||
|         try: | ||||
|             for nom, valeur in reader.composants.items(): | ||||
|                 if valeur.type == "ContactTravail": | ||||
|                     self.composants[valeur.donnees["relais"]].add_travail(nom) | ||||
|                 elif valeur.type == "ContactRepos": | ||||
|                     self.composants[valeur.donnees["relais"]].add_repos(nom) | ||||
|  | ||||
|             for nom, valeur in reader.noeuds.items(): | ||||
|                 if valeur.type == "ContactBasculeur": | ||||
|                     self.composants[valeur.donnees["relais"] + ".gauche"].add_contact(nom) | ||||
|                     self.composants[valeur.donnees["relais"] + ".droite"].add_contact(nom) | ||||
|                 elif valeur.type == "ContactDouble": | ||||
|                     self.composants[valeur.donnees["relais"]].add_double(nom) | ||||
|         except KeyError: | ||||
|             raise GraphStructException("Mauvais identificateur de relais dans un contact") | ||||
|  | ||||
|         # Construction des branches | ||||
|         for branche in reader.branches: | ||||
|             nom = self.branch_id() | ||||
|             br = me.Branche(self.conf, nom, [self.composants[x.nom] for x in branche.composants]) | ||||
|             [self.composants[x.nom].reverse() for x in branche.composants if x.nom[0] == '!']  # Diode | ||||
|             for c in br.composants: | ||||
|                 c.branche = br | ||||
|  | ||||
|             v_amont_schm, v_amont_dir = branche.get_amont() | ||||
|             v_aval_schm, v_aval_dir = branche.get_aval() | ||||
|  | ||||
|             v_amont = self.elements[v_amont_schm.nom].get_potentiel(v_amont_dir) | ||||
|             v_aval = self.elements[v_aval_schm.nom].get_potentiel(v_aval_dir) | ||||
|  | ||||
|             br.add_voisins(v_amont, v_aval) | ||||
|             v_amont.add_voisins([(br, -1, v_amont_dir)]) | ||||
|             v_aval.add_voisins([(br, +1, v_aval_dir)]) | ||||
|             self.elements[nom] = br | ||||
|             del br | ||||
|  | ||||
|         self.vecteur = Vecteur(self.elements) | ||||
|  | ||||
|     def __getitem__(self, item): | ||||
|         """ | ||||
|         Retourne un composant | ||||
|         """ | ||||
|         if item in self.composants: | ||||
|             res = self.composants[item] | ||||
|         else: | ||||
|             res = self.elements[item] | ||||
|         return res | ||||
|  | ||||
|     def __contains__(self, item): | ||||
|         return item in self.composants or item in self.elements | ||||
|  | ||||
|     def init_cycle(self): | ||||
|         [elt.init_cycle() for elt in self.elements.values()] | ||||
|  | ||||
|     def passe_calcul(self, solutions): | ||||
|         [elt.passe_calcul(solutions, self.vecteur.index(elt)) for elt in self.elements.values()] | ||||
|  | ||||
|     def update(self): | ||||
|         [elt.update() for elt in self.elements.values()] | ||||
|  | ||||
|     def coherence(self): | ||||
|         [x.coherence() for x in self.elements.values()] | ||||
							
								
								
									
										57
									
								
								modele/matrice.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,57 @@ | ||||
| import numpy as np | ||||
|  | ||||
|  | ||||
| class Matrice(object): | ||||
|     """ | ||||
|     Le système d'équation est construit sur la base d'une matrice A et un vecteur B modélisant le système, tels que | ||||
|     A.X = B | ||||
|  | ||||
|     Chaque ligne de la matrice correspond à une équation, correspondant elle-même à un élément du graphe. | ||||
|     Les équations sont dans le même ordre que les éléments du graphe. | ||||
|  | ||||
|     Chaque colonne correspond à une inconnue, également prise dans le même ordre que les éléments du graphe. | ||||
|     Si l'élément est un Potentiel ou un noeud, l'inconnue est une tension. | ||||
|     Si l'élément est une branche, l'inconnue est l'intensité parcourant la branche. | ||||
|     """ | ||||
|     def __init__(self, graphe): | ||||
|         self.vecteur = graphe.vecteur | ||||
|         self.mat_A = None | ||||
|         self.mat_B = None  # Equation matricielle AX = B | ||||
|         self.n = len(self.vecteur) | ||||
|  | ||||
|     def init_mat(self): | ||||
|         self.mat_A = np.zeros((self.n, self.n)) | ||||
|         self.mat_B = np.zeros(self.n) | ||||
|  | ||||
|         for ligne, element in enumerate(self.vecteur):  # Potentiel constant | ||||
|             # assert ligne == self.vecteur.index(element) | ||||
|             if element.type_potentiel == element.P_CST: | ||||
|                 # Potentiel constant : on ajoute une équation indiquant la valeur de la tension pour cette variable | ||||
|                 self.mat_A[ligne][ligne] = 1.0  # à noter que par construction, ligne == index | ||||
|                 self.mat_B[ligne] = element.u() | ||||
|  | ||||
|             elif element.type_potentiel == element.P_NOEUD:  # On applique la loi des noeuds | ||||
|                 # Noeud : on ajoute une équation sur la somme des intensités | ||||
|                 for (voisin, polarite, _) in element.voisins(): | ||||
|                     self.mat_A[ligne][self.vecteur.index(voisin)] = polarite | ||||
|                 self.mat_B[ligne] = 0.0 | ||||
|  | ||||
|             elif element.type_potentiel == element.P_DLT:  # On applique la loi d'Ohm | ||||
|                 self.mat_A[ligne][ligne] = 1.0 | ||||
|                 self.mat_A[ligne][self.vecteur.index(element.amont)] = -1.0 / element.r() | ||||
|                 self.mat_A[ligne][self.vecteur.index(element.aval)] = 1.0 / element.r() | ||||
|                 self.mat_B[ligne] = 0.0 | ||||
|  | ||||
|             elif element.type_potentiel == element.P_COND:  # DU = q/C | ||||
|                 self.mat_A[ligne][self.vecteur.index(element.amont)] = 1.0 | ||||
|                 self.mat_A[ligne][self.vecteur.index(element.aval)] = -1.0 | ||||
|                 self.mat_B[ligne] = element.coef_mul_tension * element.q / element.capacite | ||||
|  | ||||
|             else: | ||||
|                 assert False, "Rien à faire là" | ||||
|  | ||||
|     def solve(self): | ||||
|         """ | ||||
|         Résout le système d'équation et retourne le vecteur solution. | ||||
|         """ | ||||
|         return np.linalg.solve(self.mat_A, self.mat_B) | ||||
							
								
								
									
										3
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| numpy>=1.24.3 | ||||
| flask>=2.3.2 | ||||
| Flask-Cors>=4.0.0 | ||||
							
								
								
									
										6
									
								
								run.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| from api_server.app import main | ||||
|  | ||||
| import sys | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main(sys.argv) | ||||
							
								
								
									
										1
									
								
								schemas_v1/basculeur.ccs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| {"blocs":{"p24-1":{"type":"P24","valeur":24,"x":0,"y":526},"b1":{"type":"Bouton","x":100,"y":526,"orientation":0},"rbas":{"type":"RelaisBasculeur","x":200,"y":520,"orientation":0},"b2":{"type":"Bouton","x":350,"y":526,"orientation":180},"p24-2":{"type":"P24","valeur":24,"x":450,"y":526,"orientation":180},"p0-1":{"type":"P0","x":0,"y":512,"orientation":180},"p0-2":{"type":"P0","x":450,"y":512,"orientation":0},"p0-3":{"type":"P0","x":0,"y":299,"orientation":180},"p0-4":{"type":"P0","x":450,"y":299,"orientation":0},"l3":{"type":"Lampe","x":100,"y":299,"orientation":0},"l4":{"type":"Lampe","x":350,"y":299,"orientation":0},"rbas.basc":{"type":"ContactBasculeur","relais":"rbas","x":200,"y":285,"orientation":0},"p24-3":{"type":"P24","x":150,"y":258.2}},"cables":[["p24-1","d","b1","g"],["b1","d","rbas","hg"],["p0-1","d","rbas","bg"],["p24-2","g","b2","d"],["b2","g","rbas","hd"],["p0-2","g","rbas","bd"],["p0-3","d","l3","g"],["p0-4","g","l4","d"],["l3","d","rbas.basc","g"],["l4","g","rbas.basc","d"],["p24-3","d","rbas.basc","b"]]} | ||||
							
								
								
									
										104
									
								
								schemas_v1/condensateur.ccs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,104 @@ | ||||
| { | ||||
|     "blocs": { | ||||
|         "p24-1": { | ||||
|             "type": "P24", | ||||
|             "valeur": 24.0, | ||||
|             "x": 0, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "p0-1": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 1200, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "p0-2": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 1200, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "p0-3": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 600, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "xx": { | ||||
|             "type": "Noeud", | ||||
|             "x": 300, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "yy": { | ||||
|             "type": "Coude", | ||||
|             "x": 300, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "k1": { | ||||
|             "type": "Condensateur", | ||||
|             "capacite": 0.4, | ||||
|             "coef_mul_tension": 24, | ||||
|             "x": 400, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "r2": { | ||||
|             "type": "Relais", | ||||
|             "x": 1000, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "c3": { | ||||
|             "type": "Bouton", | ||||
|             "x": 200, | ||||
|             "y": 500, | ||||
|             "orientation": 180 | ||||
|         }, | ||||
|         "r2.travail": { | ||||
|             "type": "ContactTravail", | ||||
|             "relais": "r2", | ||||
|             "x": 1000, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "w1": { | ||||
|             "type": "Lampe", | ||||
|             "x": 600, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "n1": { | ||||
|             "type": "Noeud", | ||||
|             "x": 800, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "coude1": { | ||||
|             "type": "Coude", | ||||
|             "x": 800, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "b2": { | ||||
|                 "type": "Bouton", | ||||
|                 "x": 400, | ||||
|                 "y": 300 | ||||
|             }, | ||||
|         "w2": { | ||||
|                 "type": "Resistance", | ||||
|                 "valeur": 20, | ||||
|                 "x": 500, | ||||
|                 "y": 300 | ||||
|             } | ||||
|     }, | ||||
|     "cables": [ | ||||
|         ["p24-1", "d", "c3", "g"], | ||||
|         ["c3", "d", "xx", "m"], | ||||
|         ["xx", "m", "k1", "g"], | ||||
|         ["k1", "d", "w1", "g"], | ||||
|         ["w1", "d", "n1", "m"], | ||||
|         ["n1", "m", "r2", "g"], | ||||
|         ["r2", "d", "p0-1", "g"], | ||||
|         ["n1", "m", "coude1", "m"], | ||||
|         ["coude1", "m", "r2.travail", "g"], | ||||
|         ["r2.travail", "d", "p0-2", "g"], | ||||
|         ["xx", "m", "yy", "m"], | ||||
|         ["yy", "m", "b2", "g"], | ||||
|         ["b2", "d", "w2", "g"], | ||||
|         ["w2", "d", "p0-3", "g"] | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										87
									
								
								schemas_v1/contact_double.ccs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | ||||
| { | ||||
|     "blocs": { | ||||
|         "p24-1": { | ||||
|             "type": "P24", | ||||
|             "valeur": 24.0, | ||||
|             "orientation": 0, | ||||
|             "x": 0.0, | ||||
|             "y": 500.0 | ||||
|         }, | ||||
|         "p24-2": { | ||||
|             "type": "P24", | ||||
|             "valeur": 24.0, | ||||
|             "orientation": 0, | ||||
|             "x": 0.0, | ||||
|             "y": 300.0 | ||||
|         }, | ||||
|         "p0-1": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "orientation": 0, | ||||
|             "x": 1200.0, | ||||
|             "y": 500.0 | ||||
|         }, | ||||
|         "p0-2": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 1200.0, | ||||
|             "y": 300.0 | ||||
|         }, | ||||
|         "r1": { | ||||
|             "type": "Relais", | ||||
|             "x": 400.0, | ||||
|             "y": 500.0 | ||||
|         }, | ||||
|         "r2": { | ||||
|             "type": "Relais", | ||||
|             "x": 1000.0, | ||||
|             "y": 500.0 | ||||
|         }, | ||||
|         "c3": { | ||||
|             "type": "Bouton", | ||||
|             "x": 200.0, | ||||
|             "y": 500.0, | ||||
|             "orientation": 0 | ||||
|         }, | ||||
|         "r2.double": { | ||||
|             "type": "ContactDouble", | ||||
|             "relais": "r2", | ||||
|             "orientation": 0, | ||||
|             "x": 1000.0, | ||||
|             "y": 300.0 | ||||
|         }, | ||||
|         "w1": { | ||||
|             "type": "Lampe", | ||||
|             "x": 600.0, | ||||
|             "y": 500.0 | ||||
|         }, | ||||
|         "w2": { | ||||
|             "type": "Lampe", | ||||
|             "x": 600.0, | ||||
|             "y": 300.0 | ||||
|         }, | ||||
|         "n1": { | ||||
|             "type": "Noeud", | ||||
|             "x": 800.0, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "coude1": { | ||||
|             "type": "Coude", | ||||
|             "x": 800, | ||||
|             "y": 310 | ||||
|         } | ||||
|     }, | ||||
|     "cables": [ | ||||
|         ["p24-1", "d", "c3", "g"], | ||||
|         ["c3", "d", "r1", "g"], | ||||
|         ["r1", "d", "w1", "g"], | ||||
|         ["w1", "d", "n1", "m"], | ||||
|         ["n1", "m", "r2", "g"], | ||||
|         ["r2", "d", "p0-1", "g"], | ||||
|         ["n1", "m", "coude1", "m"], | ||||
|         ["coude1", "m", "r2.double", "hg"], | ||||
|         ["r2.double", "d", "p0-2", "g"], | ||||
|         ["p24-2", "d", "w2", "g"], | ||||
|         ["w2", "d", "r2.double", "bg"] | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										73
									
								
								schemas_v1/contact_double_180.ccs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | ||||
| { | ||||
|     "blocs": { | ||||
|         "p24": { | ||||
|             "type": "P24", | ||||
|             "valeur": 24.0, | ||||
|             "x": 0, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "b": { | ||||
|             "type": "Levier", | ||||
|             "x": 100, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "r": { | ||||
|             "type": "Relais", | ||||
|             "x": 200, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "p0-1": { | ||||
|             "type": "P0", | ||||
|             "x": 400, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "pulse": { | ||||
|             "type": "Pulse", | ||||
|             "valeur": 24.0, | ||||
|             "periode": 0.5, | ||||
|             "x": 0, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "r.double": { | ||||
|             "type": "ContactDouble", | ||||
|             "relais": "r", | ||||
|             "orientation": 180, | ||||
|             "x": 200, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "l1": { | ||||
|             "type": "Lampe", | ||||
|             "x": 300, | ||||
|             "y": 330 | ||||
|         }, | ||||
|         "l2": { | ||||
|             "type": "Lampe", | ||||
|             "x": 300, | ||||
|             "y": 270 | ||||
|         }, | ||||
|         "p0-2": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 400, | ||||
|             "y": 330 | ||||
|         }, | ||||
|         "p0-3": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 400, | ||||
|             "y": 270 | ||||
|         } | ||||
|     }, | ||||
|     "cables": [ | ||||
|         ["p24", "d", "b", "g"], | ||||
|         ["b", "d", "r", "g"], | ||||
|         ["r", "d", "p0-1", "g"], | ||||
|  | ||||
|         ["pulse", "d", "r.double", "g"], | ||||
|         ["r.double", "hd", "l1", "g"], | ||||
|         ["l1", "d", "p0-2", "g"], | ||||
|  | ||||
|         ["r.double", "bd", "l2", "g"], | ||||
|         ["l2", "d", "p0-3", "g"] | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										68
									
								
								schemas_v1/diodes.ccs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | ||||
| { | ||||
|     "blocs": { | ||||
|         "pulse": { | ||||
|             "type": "Pulse", | ||||
|             "valeur": 24.0, | ||||
|             "periode": 1, | ||||
|             "x": 0, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "noeud": { | ||||
|             "type": "Noeud", | ||||
|             "x": 200, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "coude2": { | ||||
|             "type": "Coude", | ||||
|             "x": 200, | ||||
|             "y": 300 | ||||
|         }, | ||||
|  | ||||
|         "diode1": { | ||||
|             "type": "Diode", | ||||
|             "orientation": 0, | ||||
|             "x": 350, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "diode2": { | ||||
|             "type": "Diode", | ||||
|             "orientation": 180, | ||||
|             "x": 350, | ||||
|             "y": 300 | ||||
|         }, | ||||
|  | ||||
|         "p0-1": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 600, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "p0-2": { | ||||
|             "type": "P0", | ||||
|             "valeur": 0.0, | ||||
|             "x": 600, | ||||
|             "y": 300 | ||||
|         }, | ||||
|         "l1": { | ||||
|             "type": "Lampe", | ||||
|             "x": 450, | ||||
|             "y": 500 | ||||
|         }, | ||||
|         "l2": { | ||||
|             "type": "Lampe", | ||||
|             "x": 450, | ||||
|             "y": 300 | ||||
|         } | ||||
|  | ||||
|     }, | ||||
|     "cables": [ | ||||
|         ["pulse", "d", "noeud", "m"], | ||||
|         ["noeud", "m", "diode1", "g"], | ||||
|         ["diode1", "d", "l1", "g"], | ||||
|         ["l1", "d", "p0-1", "g"], | ||||
|         ["noeud", "m", "coude2", "m"], | ||||
|         ["coude2", "m", "diode2", "g"], | ||||
|         ["diode2", "d", "l2", "g"], | ||||
|         ["l2", "d", "p0-2", "g"] | ||||
|     ] | ||||
| } | ||||