157 lines
5.9 KiB
Python
157 lines
5.9 KiB
Python
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())
|