Files
encoach_backend_new_v2/odoo/addons/iot_drivers/interface.py
Yamen Ahmad 3e83d8d7d5 feat: add complete EnCoach backend — Odoo 19 + all addons
Includes:
- Odoo 19 framework (odoo/)
- 27 custom EnCoach addons (new_project/custom_addons/)
  - encoach_core, encoach_api, encoach_lms_api, encoach_adaptive_api
  - encoach_exam, encoach_taxonomy, encoach_adaptive, encoach_assignment
  - encoach_ai, encoach_ai_grading, encoach_ai_generation, encoach_ai_media
  - encoach_courseware, encoach_communication, encoach_subscription
  - encoach_notification, encoach_approval, encoach_branding
  - encoach_classroom, encoach_registration, encoach_stats
  - encoach_faq, encoach_ticket, encoach_training, encoach_resources
  - encoach_adaptive_ai, encoach_sis
- 21 OpenEduCat Enterprise modules (new_project/enterprise-19/)
- 14 OpenEduCat Community modules (new_project/openeducat_erp-19.0/)
- Configuration: odoo.conf, requirements.txt, scripts
- 200+ REST API endpoints with JWT authentication
- SRS and test documentation

Made-with: Cursor
2026-04-01 17:10:04 +04:00

91 lines
3.4 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from threading import Thread
import time
from odoo.addons.iot_drivers.main import drivers, interfaces, iot_devices, unsupported_devices
_logger = logging.getLogger(__name__)
class Interface(Thread):
_loop_delay = 3 # Delay (in seconds) between calls to get_devices or 0 if it should be called only once
connection_type = ''
allow_unsupported = False
def __init__(self):
super().__init__(daemon=True)
self._detected_devices = set()
self.drivers = sorted([d for d in drivers if d.connection_type == self.connection_type], key=lambda d: d.priority, reverse=True)
def __init_subclass__(cls):
super().__init_subclass__()
interfaces[cls.__name__] = cls
def run(self):
while self.connection_type and self.drivers:
self.update_iot_devices(self.get_devices())
if not self._loop_delay:
break
time.sleep(self._loop_delay)
def add_device(self, identifier, device):
if identifier in iot_devices:
return
supported_driver = next(
(driver for driver in self.drivers if driver.supported(device)),
None
)
if supported_driver:
_logger.info('Device %s is now connected', identifier)
if identifier in unsupported_devices:
del unsupported_devices[identifier]
d = supported_driver(identifier, device)
iot_devices[identifier] = d
# Start the thread after creating the iot_devices entry so the
# thread can assume the iot_devices entry will exist while it's
# running, at least until the `disconnect` above gets triggered
# when `removed` is not empty.
d.start()
elif self.allow_unsupported and identifier not in unsupported_devices:
_logger.info('Unsupported device %s is now connected', identifier)
unsupported_devices[identifier] = {
'name': f'Unknown device ({self.connection_type})',
'identifier': identifier,
'type': 'unsupported',
'connection': 'direct' if self.connection_type == 'usb' else self.connection_type,
}
def remove_device(self, identifier):
if identifier in iot_devices:
iot_devices[identifier].disconnect()
_logger.info('Device %s is now disconnected', identifier)
elif self.allow_unsupported and identifier in unsupported_devices:
del unsupported_devices[identifier]
_logger.info('Unsupported device %s is now disconnected', identifier)
def update_iot_devices(self, devices=None):
if devices is None:
devices = {}
added = devices.keys() - self._detected_devices
removed = self._detected_devices - devices.keys()
unsupported = {device for device in unsupported_devices if device in devices}
self._detected_devices = set(devices.keys())
for identifier in removed:
self.remove_device(identifier)
for identifier in added | unsupported:
self.add_device(identifier, devices[identifier])
def get_devices(self):
raise NotImplementedError()
def start(self):
try:
super().start()
except Exception:
_logger.exception("Interface %s could not be started", str(self))