hw_drivers/interface.py

71 lines
3.0 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from threading import Thread
import time
from odoo.addons.hw_drivers.main import drivers, interfaces, iot_devices
_logger = logging.getLogger(__name__)
class InterfaceMetaClass(type):
def __new__(cls, clsname, bases, attrs):
new_interface = super(InterfaceMetaClass, cls).__new__(cls, clsname, bases, attrs)
interfaces[clsname] = new_interface
return new_interface
class Interface(Thread, metaclass=InterfaceMetaClass):
_loop_delay = 3 # Delay (in seconds) between calls to get_devices or 0 if it should be called only once
_detected_devices = {}
connection_type = ''
def __init__(self):
super(Interface, self).__init__()
self.drivers = sorted([d for d in drivers if d.connection_type == self.connection_type], key=lambda d: d.priority, reverse=True)
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 update_iot_devices(self, devices={}):
added = devices.keys() - self._detected_devices
removed = self._detected_devices - devices.keys()
# keys() returns a dict_keys, and the values of that stay in sync with the
# original dictionary if it changes. This means that get_devices needs to return
# a newly created dictionary every time. If it doesn't do that and reuses the
# same dictionary, this logic won't detect any changes that are made. Could be
# avoided by converting the dict_keys into a regular dict. The current logic
# also can't detect if a device is replaced by a different one with the same
# key. Also, _detected_devices starts out as a class variable but gets turned
# into an instance variable here. It would be better if it was an instance
# variable from the start to avoid confusion.
self._detected_devices = devices.keys()
for identifier in removed:
if identifier in iot_devices:
iot_devices[identifier].disconnect()
_logger.info('Device %s is now disconnected', identifier)
for identifier in added:
for driver in self.drivers:
if driver.supported(devices[identifier]):
_logger.info('Device %s is now connected', identifier)
d = driver(identifier, devices[identifier])
d.daemon = True
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()
break
def get_devices(self):
raise NotImplementedError()