Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,2 @@
from . import iot_device
from . import iot_device_input

View file

@ -0,0 +1,77 @@
import logging
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
class IotDevice(models.Model):
_inherit = "iot.device"
input_ids = fields.One2many("iot.device.input", inverse_name="device_id")
input_count = fields.Integer(compute="_compute_input_count")
@api.depends("input_ids")
def _compute_input_count(self):
for r in self:
r.input_count = len(r.input_ids)
def action_show_input(self):
self.ensure_one()
action = self.env.ref("iot_input_oca.iot_device_input_action")
result = action.read()[0]
result["context"] = {
"default_device_id": self.id,
}
result["domain"] = [("device_id", "=", self.id)]
if len(self.input_ids) == 1:
result["views"] = [(False, "form")]
result["res_id"] = self.input_ids.id
return result
def parse_single_input(self, uuid=False, address=False, **kwargs):
"""Handle single input for device
:param dict value:
Dict containing at least keys 'address', 'value'
:returns: dict with keys 'status', 'message' where:
- status='ok' when value is parsed without errors
- status='error' and message='error message' when error occurs
If value contains a value with key 'uuid', it is passed in the return dict
to identify result for each entry at the iot end
:rtype: dict
"""
msg = {}
if uuid:
msg["uuid"] = uuid
if not address:
_logger.warning("Address for Input is required")
msg.update(
{"status": "error", "message": _("Address for Input is required")}
)
return msg
device_input = self.input_ids.filtered(lambda i: i.address == str(address))
if len(device_input) == 1:
if not device_input.active:
_logger.warning(
"Input with address %s is inactive, no data will be logged",
device_input.address,
)
msg.update(
{
"status": "error",
"message": _("Server Error. Check server logs"),
}
)
return msg
res = device_input.call_device(**kwargs)
if uuid:
res["uuid"] = uuid
return res
else:
_logger.warning("Input with address %s not found", address)
msg.update(
{"status": "error", "message": _("Server Error. Check server logs")}
)
return msg

View file

@ -0,0 +1,146 @@
import logging
import traceback
from io import StringIO
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
class IotDeviceInput(models.Model):
_name = "iot.device.input"
_description = "Device input"
_order = "name"
name = fields.Char(required=True)
device_id = fields.Many2one(
"iot.device", required=True, readonly=True, auto_join=True
)
call_model_id = fields.Many2one("ir.model")
call_function = fields.Char(required=True)
active = fields.Boolean(default=True)
serial = fields.Char()
address = fields.Char()
passphrase = fields.Char()
action_ids = fields.One2many(
"iot.device.input.action",
inverse_name="input_id",
readonly=True,
)
action_count = fields.Integer(compute="_compute_action_count")
lang = fields.Selection(
selection=lambda self: self.env["res.lang"].get_installed(),
string="Language",
)
@api.depends("action_ids")
def _compute_action_count(self):
for r in self:
r.action_count = len(r.action_ids)
def _call_device(self, *args, **kwargs):
self.ensure_one()
obj = self
if self.call_model_id:
obj = self.env[self.call_model_id.model].with_context(
iot_device_input_id=self.id,
iot_device_name=self.device_id.name,
iot_device_id=self.device_id.id,
)
if self.lang:
obj = obj.with_context(lang=self.lang)
return getattr(obj, self.call_function)(*args, **kwargs)
def parse_args(self, serial, passphrase):
if not serial or not passphrase:
raise ValidationError(_("Serial and passphrase are required"))
return [
("serial", "=", serial),
("passphrase", "=", passphrase),
("device_id.active", "=", True),
]
@api.model
def get_device(self, serial, passphrase):
return self.search(self.parse_args(serial, passphrase), limit=1)
def call_device(self, **kwargs):
if not self:
return {"status": "error", "message": _("Device cannot be found")}
new_kwargs = kwargs.copy()
args = []
if "value" in new_kwargs and len(new_kwargs) == 1:
args.append(new_kwargs.pop("value"))
try:
# We want to control that if an error happens,
# everything will return to normal but we can process it properly
with self.env.cr.savepoint():
res = self._call_device(*args, **new_kwargs)
if not res.get("status"):
res["status"] = "ok"
error = False
except self._swallable_exceptions():
buff = StringIO()
traceback.print_exc(file=buff)
error = buff.getvalue()
_logger.error(error)
res = {"status": "ko"}
self.device_id.last_contact_date = fields.Datetime.now()
self.env["iot.device.input.action"].create(
self._add_action_vals(res, error, args, new_kwargs)
)
return res
def _swallable_exceptions(self):
# TODO: improve this list
return (UserError, ValidationError, AttributeError, TypeError)
def _add_action_vals(self, res, error, args, kwargs):
new_res = res.copy()
if error:
new_res["error"] = error
return {
"input_id": self.id,
"args": str(args or kwargs),
"res": str(res),
}
def test_input_device(self, value):
return {"value": value}
def test_model_function(self, value):
return {"status": "ok", "message": value}
def parse_multi_input(self, values):
"""Handle multiple inputs for device
:param list values:
Values is a list of dicts with at least values for keys 'address', 'value'
Each dict in the list can have:
- Different address (multi input)
- Same address, different values (multi event)
- Mix of the above (multi input, multi event)
:returns: JSON encodable list of dicts
:rtype: list
"""
device = self.device_id
if not values:
_logger.warning(
"Empty values array for input with identification %s",
self.serial,
)
return {"status": "ko"}
res = []
for d in values:
res.append(device.parse_single_input(**d))
return {"result": res}
class IoTDeviceAction(models.Model):
_name = "iot.device.input.action"
_description = "Action of device inputs"
input_id = fields.Many2one("iot.device.input")
args = fields.Char()
kwargs = fields.Char()
res = fields.Char()