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,157 @@
=========
IoT Input
=========
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4027dfc83e42e31e5a186fd4a2fd0d7e1bb0829ed30f9395c9053177d9b13140
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fiot-lightgray.png?logo=github
:target: https://github.com/OCA/iot/tree/16.0/iot_input_oca
:alt: OCA/iot
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/iot-16-0/iot-16-0-iot_input_oca
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/iot&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This addon allows to use a device in order to input data to odoo automatically.
It opens a URL that a device can use to connect (with a password) that can only
execute an specific action.
Inputs are useful when a device wants to communicate to odoo for a single
and simple action.
This way, the device does not need to be configured with a odoo user and
password, it is handled by odoo devices.
Examples:
* Sending the temperature every three minutes.
* Sending the RFID that the device has received in order to perform some action
**Table of contents**
.. contents::
:local:
Usage
=====
There are two endpoints you can use:
Endpoint 1: /iot/<serial>/action
Takes `application/x-www-form-urlencoded` parameters:
passphase, value (where value is a JSON object)
1. Create a Device on `IoT > Config Devices`
2. Access the Inputs section of the device
3. Create an input. You must define a serial, passphrase, function and model
The function that the system will call must be of the following kind::
@api.model
def call_function(self, key):
return {}
Where `key` is the input string send by the device and the result must be a dictionary
that will be responded to the device as a JSON.
Endpoint 2: /iot/<device_identification>/multi_input
It can be used to send values with multiple data in one POST request such as:
- Values for inputs of the same device with different address (multi input)
- Values for inputs of the same device with same address, different values (multi event)
- Mix of the above (multi input, multi event)
Takes `application/x-www-form-urlencoded` parameters:
passphase, values (a JSON array of JSON objects)
It is called using device_identification and passing two POST parameters: device passphrase and
a JSON string containing an array of values for input
- The value for the `address` key can be a string or a numeric (to conserve bytes in memory
restricted devices when creating the JSON object) and is converted to string when parsing.
- The value for the `value` key can either be string, number or boolean according to
JSON specs.
You can see an example of a valid JSON input object in the examples folder, using a few
combinations.
It requires the function that the system will call must be of the following kind::
@api.model
def call_function(self, key):
'do something
if err:
return {'status': 'error', 'message': 'The error message you want to send to the device'}
return {'status': 'ok', 'message': 'Optional success message'}
Where `key` is a dict send by the device having at least value for keys: 'address', 'value'
The function must always return a JSON with status and message. If value contains a value
with 'uuid' as key, it is returned along with the object for the IoT device to identify
success/failure per record.
It has full error reporting and the return value is a JSON array of dicts containing at
least status and message. Error message respose is at some points generic, though
extended logging is done in Odoo server logs.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/iot/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/iot/issues/new?body=module:%20iot_input_oca%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Creu Blanca
Contributors
~~~~~~~~~~~~
* Enric Tobella <etobella@creublanca.es>
* Dimitrios Tanis <dtanis@tanisfood.gr>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px
:target: https://github.com/etobella
:alt: etobella
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-etobella|
This module is part of the `OCA/iot <https://github.com/OCA/iot/tree/16.0/iot_input_oca>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,2 @@
from . import models
from . import controller

View file

@ -0,0 +1,19 @@
# Copyright (C) 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "IoT Input",
"version": "16.0.1.0.1",
"author": "Creu Blanca, Odoo Community Association (OCA)",
"category": "IoT",
"license": "AGPL-3",
"installable": True,
"summary": "IoT Input module",
"depends": ["iot_oca"],
"website": "https://github.com/OCA/iot",
"maintainers": ["etobella"],
"data": [
"security/ir.model.access.csv",
"views/iot_device_views.xml",
"views/iot_device_input_views.xml",
],
}

View file

@ -0,0 +1 @@
from . import iot_input_controller

View file

@ -0,0 +1,105 @@
# Copyright 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import json
import logging
from odoo import _, http
_logger = logging.getLogger(__name__)
class CallIot(http.Controller):
@http.route(
["/iot/<serial>/action"],
type="http",
auth="none",
methods=["POST"],
csrf=False,
)
def call_unauthorized_iot(self, serial, passphrase=False, *args, **kwargs):
request = http.request
if not request.env:
return json.dumps(False)
return json.dumps(
request.env["iot.device.input"]
.sudo()
.get_device(serial, passphrase)
.call_device(**kwargs)
)
@http.route(
["/iot/<serial>/multi_input"],
type="http",
auth="none",
methods=["POST"],
csrf=False,
)
def call_unauthorized_iot_multi_input(
self, serial, passphrase=False, values=False, *args, **kwargs
):
"""Controller to write multiple input data to device inputs
:param string passphrase:
Device passphrase in POST data.
:param string values:
JSON formatted string containing a JSON an array of JSON objects.
"""
request = http.request
if not request.env:
_logger.warning("env not set")
return json.dumps({"status": "error", "message": _("Server Error")})
if not passphrase:
_logger.warning("Passphrase is required")
return json.dumps(
{"status": "error", "message": _("Passphrase is required")}
)
if not values:
_logger.warning("Values is required")
return json.dumps({"status": "error", "message": _("Values is required")})
# Decode JSON object here and use pure python objects in further calls
try:
if isinstance(values, str):
values = json.loads(values)
if not isinstance(values, list):
raise SyntaxError
except json.decoder.JSONDecodeError:
_logger.warning("Values is not a valid JSON")
return json.dumps(
{"status": "error", "message": _("Values is not a valid JSON")}
)
except SyntaxError:
_logger.warning("Values should be a JSON array of JSON objects")
return json.dumps(
{
"status": "error",
"message": _("Values should be a JSON array of JSON objects"),
}
)
# Encode response to JSON and return
result = (
request.env["iot.device.input"]
.sudo()
.get_device(serial, passphrase)
.call_device(values=values)
)
if result["status"] != "ok":
return json.dumps({"status": result["status"]})
return json.dumps(result["result"])
@http.route(
["/iot/<serial>/check"], type="http", auth="none", methods=["POST"], csrf=False
)
def check_unauthorized_iot(self, serial, *args, **kwargs):
request = http.request
if not request.env:
return json.dumps(False)
device = (
request.env["iot.device.input"]
.sudo()
.get_device(serial, kwargs["passphrase"])
)
if device:
return json.dumps({"state": True})
return json.dumps({"state": False})

View file

@ -0,0 +1,19 @@
[
{
"address": "ZMPT101B_1",
"value": 230
},
{
"address": 1,
"value": true
},
{
"address": 2,
"value": "Door opened",
"uuid": "abcde"
},
{
"address": 10,
"value": -18.5
}
]

View file

@ -0,0 +1,250 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__action_ids
msgid "Action"
msgstr "Akcija"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__action_count
msgid "Action Count"
msgstr "Broj akcija"
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device_input_action
msgid "Action of device inputs"
msgstr "Akcija unosa uređaja"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "Active"
msgstr "Aktivan"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__address
msgid "Address"
msgstr "Adresa"
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:54
#, python-format
msgid "Address for Input is required"
msgstr "Adresa za unos je potrebna"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__args
msgid "Args"
msgstr "Argumenti"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__call_function
msgid "Call Function"
msgstr "Pozovi funkciju"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr "Pozovi model"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr "Kreirao"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__create_date
msgid "Created on"
msgstr "Kreirano"
#. module: iot_input
#: code:addons/iot_input/models/mail_message.py:15
#, python-format
msgid "Detected automatically by %s"
msgstr "Automatski otkriveno od %s"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__device_id
msgid "Device"
msgstr "Uređaj"
#. module: iot_input
#: code:addons/iot_input/models/iot_device_input.py:61
#, python-format
msgid "Device cannot be found"
msgstr "Uređaj se ne može pronaći"
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device_input
msgid "Device input"
msgstr "Unos uređaja"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr "Prikazani naziv"
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:136
#, python-format
msgid "Empty values array"
msgstr "Prazan niz vrijednosti"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__id
msgid "ID"
msgstr "ID"
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "Inactive"
msgstr "Neaktivan"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__input_id
msgid "Input"
msgstr "Ulaz"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device__input_count
msgid "Input Count"
msgstr "Broj unosa"
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_form
msgid "Inputs"
msgstr "Ulazi"
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device
msgid "IoT Device"
msgstr "IoT uređaj"
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "IoT Device Input Search"
msgstr "Pretraga unosa IoT uređaja"
#. module: iot_input
#: model:ir.actions.act_window,name:iot_input.iot_device_input_action
msgid "IoT Inputs"
msgstr "IoT unosi"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__lang
msgid "Language"
msgstr "Jezik"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr "Zadnje mijenjano"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr "Zadnji ažurirao"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr "Zadnje ažurirano"
#. module: iot_input
#: model:ir.model,name:iot_input.model_mail_message
msgid "Message"
msgstr "Poruka"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__name
msgid "Name"
msgstr "Naziv:"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr "Parolska fraza"
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:43
#, python-format
msgid "Passphrase is required"
msgstr "Parolska fraza je potrebna"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__res
msgid "Res"
msgstr "Res"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__serial
msgid "Serial"
msgstr "Serijski broj"
#. module: iot_input
#: code:addons/iot_input/models/iot_device_input.py:47
#, python-format
msgid "Serial and passphrase are required"
msgstr "Serijski broj i parolska fraza su potrebni"
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:39
#, python-format
msgid "Server Error"
msgstr "Greška poslužitelja"
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:74
#: code:addons/iot_input/models/iot_device.py:87
#: code:addons/iot_input/models/iot_device.py:117
#: code:addons/iot_input/models/iot_device.py:123
#: code:addons/iot_input/models/iot_device.py:129
#, python-format
msgid "Server Error. Check server logs"
msgstr "Greška servera. Provjerite zapisnike servera"
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:61
#, python-format
msgid "Value for Input is required"
msgstr "Vrijednost za unos je potrebna"
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:56
#, python-format
msgid "Values is not a valid JSON"
msgstr "Vrijednosti nisu važeći JSON"
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:47
#, python-format
msgid "Values is required"
msgstr "Vrijednosti su potrebne"
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:61
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr "Vrijednosti trebaju biti JSON niz JSON objekata"

View file

@ -0,0 +1,246 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input_oca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2022-06-03 11:05+0000\n"
"Last-Translator: jabelchi <jabelchi@gmail.com>\n"
"Language-Team: none\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban
msgid ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Inputs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids
msgid "Action"
msgstr "Acció"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_count
msgid "Action Count"
msgstr "Nombre d'accions"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input_action
msgid "Action of device inputs"
msgstr "Acció d'entrades de dispositiu"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Active"
msgstr "Actiu"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address
msgid "Address"
msgstr "Adreça"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Address for Input is required"
msgstr "L'adreça d'entrada és necessària"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__args
msgid "Args"
msgstr "Args"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_function
msgid "Call Function"
msgstr "Crida a la funció"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr "Creat per"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_date
msgid "Created on"
msgstr "Creat el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__device_id
msgid "Device"
msgstr "Dispositiu"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Device cannot be found"
msgstr "No es troba el dispositiu"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input
msgid "Device input"
msgstr "Entrada de dispositiu"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr "Nom a mostrar"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__id
msgid "ID"
msgstr "ID"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Inactive"
msgstr "Inactiu"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__input_id
msgid "Input"
msgstr "Entrada"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count
msgid "Input Count"
msgstr "Nombre d'entrades"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form
msgid "Inputs"
msgstr "Entrades"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device
msgid "IoT Device"
msgstr "Dispositiu IoT"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "IoT Device Input Search"
msgstr "Cerca de dispositius IoT"
#. module: iot_input_oca
#: model:ir.actions.act_window,name:iot_input_oca.iot_device_input_action
msgid "IoT Inputs"
msgstr "Entrades IoT"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__kwargs
msgid "Kwargs"
msgstr "Kwargs"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang
msgid "Language"
msgstr "Idioma"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr "Darrera modificació el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr "Darrera actualització per"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr "Darrera actualització el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__name
msgid "Name"
msgstr "Nom"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr "Contrasenya"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Passphrase is required"
msgstr "Es requereix contrasenya"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res
msgid "Res"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial
msgid "Serial"
msgstr "Número de sèrie"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Serial and passphrase are required"
msgstr "Es requereix número de sèrie i contrasenya"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Server Error"
msgstr "Error de servidor"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Server Error. Check server logs"
msgstr "Error de servidor. Comproveu els registres del servidor"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is not a valid JSON"
msgstr "El valor no és un JSON vàlid"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is required"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr ""

View file

@ -0,0 +1,248 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input_oca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-09-03 13:40+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban
msgid ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Inputs"
msgstr ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Entradas"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids
msgid "Action"
msgstr "Acción"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_count
msgid "Action Count"
msgstr "Conteo de acciones"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input_action
msgid "Action of device inputs"
msgstr "Acción de las entradas del dispositivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Active"
msgstr "Activo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address
msgid "Address"
msgstr "Dirección"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Address for Input is required"
msgstr "Se requiere la dirección para la entrada"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__args
msgid "Args"
msgstr "Argumentos"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_function
msgid "Call Function"
msgstr "Función de llamada"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr "Modelo de llamada"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_date
msgid "Created on"
msgstr "Creado el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__device_id
msgid "Device"
msgstr "Dispositivo"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Device cannot be found"
msgstr "No se puede encontrar el dispositivo"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input
msgid "Device input"
msgstr "Entrada del dispositivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr "Mostrar Nombre"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__id
msgid "ID"
msgstr "ID (identificación)"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Inactive"
msgstr "Inactivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__input_id
msgid "Input"
msgstr "Entrada"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count
msgid "Input Count"
msgstr "Conteo de entradas"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form
msgid "Inputs"
msgstr "Entradas"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device
msgid "IoT Device"
msgstr "Dispositivo IoT"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "IoT Device Input Search"
msgstr "Búsqueda de entrada de dispositivos IoT"
#. module: iot_input_oca
#: model:ir.actions.act_window,name:iot_input_oca.iot_device_input_action
msgid "IoT Inputs"
msgstr "Entradas IoT"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__kwargs
msgid "Kwargs"
msgstr "Kwargs"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang
msgid "Language"
msgstr "Lenguaje"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr "Última Modificación el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr "Actualizado por Última vez por"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__name
msgid "Name"
msgstr "Nombre"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr "Frase de acceso"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Passphrase is required"
msgstr "Se requiere una frase de acceso"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res
msgid "Res"
msgstr "Resultado"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial
msgid "Serial"
msgstr "Serie"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Serial and passphrase are required"
msgstr "Se requiere serie y frase de contraseña"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Server Error"
msgstr "Error del servidor"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Server Error. Check server logs"
msgstr "Error del servidor. Compruebe los registros del servidor"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is not a valid JSON"
msgstr "Los valores no son un JSON válido"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is required"
msgstr "Se requieren valores"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr "Los valores deben ser una matriz de objetos JSON"

View file

@ -0,0 +1,248 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input_oca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-10-09 08:13+0000\n"
"Last-Translator: Mostafa Barmshory <mostafa.barmshory@gmail.com>\n"
"Language-Team: none\n"
"Language: fa\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban
msgid ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Inputs"
msgstr ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" ورودی‌ها"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids
msgid "Action"
msgstr "فعالیت"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_count
msgid "Action Count"
msgstr "تعداد فعالیت"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input_action
msgid "Action of device inputs"
msgstr "فعالیت از دستگاه‌های ورودی"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Active"
msgstr "فعال"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address
msgid "Address"
msgstr "آدرس"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Address for Input is required"
msgstr "آدرس برای ورودی اجباری است"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__args
msgid "Args"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_function
msgid "Call Function"
msgstr "فراخوانی عملکرد"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr "فراخوانی مدل"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr "ایجاد شده توسط"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_date
msgid "Created on"
msgstr "ایجاد شده توسط"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__device_id
msgid "Device"
msgstr "دستگاه"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Device cannot be found"
msgstr "دستگاه یافت نشد"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input
msgid "Device input"
msgstr "دستگاه ورودی"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr "نام نمایشی"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__id
msgid "ID"
msgstr "شناسه"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Inactive"
msgstr "غیر فعال"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__input_id
msgid "Input"
msgstr "ورودی"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count
msgid "Input Count"
msgstr "تعداد ورودی"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form
msgid "Inputs"
msgstr "ورودی‌ها"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device
msgid "IoT Device"
msgstr "دستگاه اینترنت اشیا"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "IoT Device Input Search"
msgstr "جستجوی دستگاه ورودی اینترنت اشیا"
#. module: iot_input_oca
#: model:ir.actions.act_window,name:iot_input_oca.iot_device_input_action
msgid "IoT Inputs"
msgstr "ورودی‌های اینترنت اشیا"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__kwargs
msgid "Kwargs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang
msgid "Language"
msgstr "زبان‌ها"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr "آخرین نگارش در"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr "آخرین به روز رسانی با"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr "آخرین به روز رسانی در"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__name
msgid "Name"
msgstr "نام"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr "گذرواژه"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Passphrase is required"
msgstr "گذرواژه اجباری است"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res
msgid "Res"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial
msgid "Serial"
msgstr "سریال"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Serial and passphrase are required"
msgstr "سریال و گذرواژه اجباری است"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Server Error"
msgstr "خطای سرور"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Server Error. Check server logs"
msgstr "خطای سرور. لاگ‌های سرور را چک کنید"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is not a valid JSON"
msgstr "مقدار یک JSON معتبر نیست"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is required"
msgstr "مقدار اجباری است"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr "مقدارها باید یک ارايه JSON از اشیا JSON باشد"

View file

@ -0,0 +1,250 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__action_ids
msgid "Action"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__action_count
msgid "Action Count"
msgstr ""
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device_input_action
msgid "Action of device inputs"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "Active"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__address
msgid "Address"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:54
#, python-format
msgid "Address for Input is required"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__args
msgid "Args"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__call_function
msgid "Call Function"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__create_date
msgid "Created on"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/mail_message.py:15
#, python-format
msgid "Detected automatically by %s"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__device_id
msgid "Device"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device_input.py:61
#, python-format
msgid "Device cannot be found"
msgstr ""
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device_input
msgid "Device input"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:136
#, python-format
msgid "Empty values array"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__id
msgid "ID"
msgstr ""
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "Inactive"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__input_id
msgid "Input"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device__input_count
msgid "Input Count"
msgstr ""
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_form
msgid "Inputs"
msgstr ""
#. module: iot_input
#: model:ir.model,name:iot_input.model_iot_device
msgid "IoT Device"
msgstr ""
#. module: iot_input
#: model_terms:ir.ui.view,arch_db:iot_input.iot_device_input_search
msgid "IoT Device Input Search"
msgstr ""
#. module: iot_input
#: model:ir.actions.act_window,name:iot_input.iot_device_input_action
msgid "IoT Inputs"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__lang
msgid "Language"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr ""
#. module: iot_input
#: model:ir.model,name:iot_input.model_mail_message
msgid "Message"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__name
msgid "Name"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:43
#, python-format
msgid "Passphrase is required"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input_action__res
msgid "Res"
msgstr ""
#. module: iot_input
#: model:ir.model.fields,field_description:iot_input.field_iot_device_input__serial
msgid "Serial"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device_input.py:47
#, python-format
msgid "Serial and passphrase are required"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:39
#, python-format
msgid "Server Error"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:74
#: code:addons/iot_input/models/iot_device.py:87
#: code:addons/iot_input/models/iot_device.py:117
#: code:addons/iot_input/models/iot_device.py:123
#: code:addons/iot_input/models/iot_device.py:129
#, python-format
msgid "Server Error. Check server logs"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/models/iot_device.py:61
#, python-format
msgid "Value for Input is required"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:56
#, python-format
msgid "Values is not a valid JSON"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:47
#, python-format
msgid "Values is required"
msgstr ""
#. module: iot_input
#: code:addons/iot_input/controller/iot_input_controller.py:61
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr ""

View file

@ -0,0 +1,244 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input_oca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban
msgid ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Inputs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids
msgid "Action"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_count
msgid "Action Count"
msgstr ""
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input_action
msgid "Action of device inputs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Active"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address
msgid "Address"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Address for Input is required"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__args
msgid "Args"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_function
msgid "Call Function"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_date
msgid "Created on"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__device_id
msgid "Device"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Device cannot be found"
msgstr ""
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input
msgid "Device input"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__id
msgid "ID"
msgstr ""
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Inactive"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__input_id
msgid "Input"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count
msgid "Input Count"
msgstr ""
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form
msgid "Inputs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device
msgid "IoT Device"
msgstr ""
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "IoT Device Input Search"
msgstr ""
#. module: iot_input_oca
#: model:ir.actions.act_window,name:iot_input_oca.iot_device_input_action
msgid "IoT Inputs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__kwargs
msgid "Kwargs"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang
msgid "Language"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__name
msgid "Name"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Passphrase is required"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res
msgid "Res"
msgstr ""
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial
msgid "Serial"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Serial and passphrase are required"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Server Error"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Server Error. Check server logs"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is not a valid JSON"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is required"
msgstr ""
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr ""

View file

@ -0,0 +1,248 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * iot_input_oca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-08-30 10:06+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban
msgid ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Inputs"
msgstr ""
"<i class=\"fa fa-keyboard-o\"/>\n"
" Input"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids
msgid "Action"
msgstr "Azione"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_count
msgid "Action Count"
msgstr "Conteggio azione"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input_action
msgid "Action of device inputs"
msgstr "Azione degli input dispositivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__active
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Active"
msgstr "Attivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address
msgid "Address"
msgstr "Indirizzo"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Address for Input is required"
msgstr "È richiesto un indirizzo per l'input"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__args
msgid "Args"
msgstr "Argomenti"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_function
msgid "Call Function"
msgstr "Richiama funzione"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__call_model_id
msgid "Call Model"
msgstr "Richiama modello"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__create_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__create_date
msgid "Created on"
msgstr "Creato il"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__device_id
msgid "Device"
msgstr "Dispositivo"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Device cannot be found"
msgstr "Dispositivo non trovato"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device_input
msgid "Device input"
msgstr "Input dispositivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__display_name
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__id
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__id
msgid "ID"
msgstr "ID"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "Inactive"
msgstr "Inattivo"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_ids
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__input_id
msgid "Input"
msgstr "Input"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count
msgid "Input Count"
msgstr "Conteggio input"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form
msgid "Inputs"
msgstr "Input"
#. module: iot_input_oca
#: model:ir.model,name:iot_input_oca.model_iot_device
msgid "IoT Device"
msgstr "Dispositivo IoT"
#. module: iot_input_oca
#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search
msgid "IoT Device Input Search"
msgstr "Ricerca input dispositivo IoT"
#. module: iot_input_oca
#: model:ir.actions.act_window,name:iot_input_oca.iot_device_input_action
msgid "IoT Inputs"
msgstr "Input IoT"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__kwargs
msgid "Kwargs"
msgstr "Kwargs"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang
msgid "Language"
msgstr "Lingua"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input____last_update
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_date
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__name
msgid "Name"
msgstr "Nome"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase
msgid "Passphrase"
msgstr "Passphrase"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Passphrase is required"
msgstr "Richiesta passphrase"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res
msgid "Res"
msgstr "Res"
#. module: iot_input_oca
#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial
msgid "Serial"
msgstr "Seriale"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device_input.py:0
#, python-format
msgid "Serial and passphrase are required"
msgstr "Richiesti seriale e passphrase"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Server Error"
msgstr "Errore server"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/models/iot_device.py:0
#, python-format
msgid "Server Error. Check server logs"
msgstr "Errore server: controllare i log del server"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is not a valid JSON"
msgstr "I valori non sono in formato JSON"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values is required"
msgstr "Richiesti valori"
#. module: iot_input_oca
#. odoo-python
#: code:addons/iot_input_oca/controller/iot_input_controller.py:0
#, python-format
msgid "Values should be a JSON array of JSON objects"
msgstr "I valori devono essere una matrice o un oggetto JSON"

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()

View file

@ -0,0 +1,2 @@
* Enric Tobella <etobella@creublanca.es>
* Dimitrios Tanis <dtanis@tanisfood.gr>

View file

@ -0,0 +1,14 @@
This addon allows to use a device in order to input data to odoo automatically.
It opens a URL that a device can use to connect (with a password) that can only
execute an specific action.
Inputs are useful when a device wants to communicate to odoo for a single
and simple action.
This way, the device does not need to be configured with a odoo user and
password, it is handled by odoo devices.
Examples:
* Sending the temperature every three minutes.
* Sending the RFID that the device has received in order to perform some action

View file

@ -0,0 +1,55 @@
There are two endpoints you can use:
Endpoint 1: /iot/<serial>/action
Takes `application/x-www-form-urlencoded` parameters:
passphase, value (where value is a JSON object)
1. Create a Device on `IoT > Config Devices`
2. Access the Inputs section of the device
3. Create an input. You must define a serial, passphrase, function and model
The function that the system will call must be of the following kind::
@api.model
def call_function(self, key):
return {}
Where `key` is the input string send by the device and the result must be a dictionary
that will be responded to the device as a JSON.
Endpoint 2: /iot/<device_identification>/multi_input
It can be used to send values with multiple data in one POST request such as:
- Values for inputs of the same device with different address (multi input)
- Values for inputs of the same device with same address, different values (multi event)
- Mix of the above (multi input, multi event)
Takes `application/x-www-form-urlencoded` parameters:
passphase, values (a JSON array of JSON objects)
It is called using device_identification and passing two POST parameters: device passphrase and
a JSON string containing an array of values for input
- The value for the `address` key can be a string or a numeric (to conserve bytes in memory
restricted devices when creating the JSON object) and is converted to string when parsing.
- The value for the `value` key can either be string, number or boolean according to
JSON specs.
You can see an example of a valid JSON input object in the examples folder, using a few
combinations.
It requires the function that the system will call must be of the following kind::
@api.model
def call_function(self, key):
'do something
if err:
return {'status': 'error', 'message': 'The error message you want to send to the device'}
return {'status': 'ok', 'message': 'Optional success message'}
Where `key` is a dict send by the device having at least value for keys: 'address', 'value'
The function must always return a JSON with status and message. If value contains a value
with 'uuid' as key, it is returned along with the object for the IoT device to identify
success/failure per record.
It has full error reporting and the return value is a JSON array of dicts containing at
least status and message. Error message respose is at some points generic, though
extended logging is done in Odoo server logs.

View file

@ -0,0 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_iot_device_input,access_iot_device_input,model_iot_device_input,iot_oca.group_iot_user,1,1,1,0
manage_iot_device_input,access_iot_device_input,model_iot_device_input,iot_oca.group_iot_manager,1,1,1,1
access_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot_oca.group_iot_user,1,1,1,0
manage_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot_oca.group_iot_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_iot_device_input access_iot_device_input model_iot_device_input iot_oca.group_iot_user 1 1 1 0
3 manage_iot_device_input access_iot_device_input model_iot_device_input iot_oca.group_iot_manager 1 1 1 1
4 access_iot_device_input_action access_iot_device_input_action model_iot_device_input_action iot_oca.group_iot_user 1 1 1 0
5 manage_iot_device_input_action access_iot_device_input_action model_iot_device_input_action iot_oca.group_iot_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,489 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>IoT Input</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="iot-input">
<h1 class="title">IoT Input</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4027dfc83e42e31e5a186fd4a2fd0d7e1bb0829ed30f9395c9053177d9b13140
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/iot/tree/16.0/iot_input_oca"><img alt="OCA/iot" src="https://img.shields.io/badge/github-OCA%2Fiot-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/iot-16-0/iot-16-0-iot_input_oca"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/iot&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This addon allows to use a device in order to input data to odoo automatically.</p>
<p>It opens a URL that a device can use to connect (with a password) that can only
execute an specific action.</p>
<p>Inputs are useful when a device wants to communicate to odoo for a single
and simple action.
This way, the device does not need to be configured with a odoo user and
password, it is handled by odoo devices.</p>
<p>Examples:</p>
<ul class="simple">
<li>Sending the temperature every three minutes.</li>
<li>Sending the RFID that the device has received in order to perform some action</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>There are two endpoints you can use:
Endpoint 1: /iot/&lt;serial&gt;/action</p>
<p>Takes <cite>application/x-www-form-urlencoded</cite> parameters:
passphase, value (where value is a JSON object)</p>
<ol class="arabic simple">
<li>Create a Device on <cite>IoT &gt; Config Devices</cite></li>
<li>Access the Inputs section of the device</li>
<li>Create an input. You must define a serial, passphrase, function and model</li>
</ol>
<p>The function that the system will call must be of the following kind:</p>
<pre class="literal-block">
&#64;api.model
def call_function(self, key):
return {}
</pre>
<p>Where <cite>key</cite> is the input string send by the device and the result must be a dictionary
that will be responded to the device as a JSON.</p>
<p>Endpoint 2: /iot/&lt;device_identification&gt;/multi_input
It can be used to send values with multiple data in one POST request such as:
- Values for inputs of the same device with different address (multi input)
- Values for inputs of the same device with same address, different values (multi event)
- Mix of the above (multi input, multi event)</p>
<p>Takes <cite>application/x-www-form-urlencoded</cite> parameters:
passphase, values (a JSON array of JSON objects)</p>
<p>It is called using device_identification and passing two POST parameters: device passphrase and
a JSON string containing an array of values for input
- The value for the <cite>address</cite> key can be a string or a numeric (to conserve bytes in memory
restricted devices when creating the JSON object) and is converted to string when parsing.
- The value for the <cite>value</cite> key can either be string, number or boolean according to
JSON specs.
You can see an example of a valid JSON input object in the examples folder, using a few
combinations.</p>
<p>It requires the function that the system will call must be of the following kind:</p>
<pre class="literal-block">
&#64;api.model
def call_function(self, key):
'do something
if err:
return {'status': 'error', 'message': 'The error message you want to send to the device'}
return {'status': 'ok', 'message': 'Optional success message'}
</pre>
<p>Where <cite>key</cite> is a dict send by the device having at least value for keys: address, value</p>
<p>The function must always return a JSON with status and message. If value contains a value
with uuid as key, it is returned along with the object for the IoT device to identify
success/failure per record.</p>
<p>It has full error reporting and the return value is a JSON array of dicts containing at
least status and message. Error message respose is at some points generic, though
extended logging is done in Odoo server logs.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/iot/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/iot/issues/new?body=module:%20iot_input_oca%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Creu Blanca</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
<li>Dimitrios Tanis &lt;<a class="reference external" href="mailto:dtanis&#64;tanisfood.gr">dtanis&#64;tanisfood.gr</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/etobella"><img alt="etobella" src="https://github.com/etobella.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/iot/tree/16.0/iot_input_oca">OCA/iot</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,3 @@
from . import test_iot_in
from . import test_iot_multi_input
from . import test_iot_controller

View file

@ -0,0 +1,10 @@
from odoo import models
class ResPartner(models.Model):
_inherit = "res.partner"
def test_fake_iot_input(self, value):
partner = self.browse(value)
partner.message_post(body=str(value))
return {}

View file

@ -0,0 +1,141 @@
import json
from odoo.tests.common import HttpCase, tagged
@tagged("post_install", "-at_install")
class TestIotController(HttpCase):
def setUp(self):
super().setUp()
self.device_identification = "test_device_name"
self.passphrase = "password"
self.system = self.env["iot.communication.system"].create(
{"name": "Demo system"}
)
self.device = self.env["iot.device"].create(
{
"name": "Device",
"communication_system_id": self.system.id,
}
)
self.address_1 = "I0"
self.serial = "testingdeviceserial"
self.input_passphrase = "password"
self.device_input_1 = self.env["iot.device.input"].create(
{
"name": "Input 1",
"device_id": self.device.id,
"address": self.address_1,
"serial": self.serial,
"passphrase": self.input_passphrase,
"call_model_id": self.env.ref(
"iot_input_oca.model_iot_device_input"
).id,
"call_function": "test_model_function",
}
)
self.address_2 = "I1"
self.env["iot.device.input"].create(
{
"name": "Input 2",
"device_id": self.device.id,
"address": self.address_2,
"call_model_id": self.env.ref(
"iot_input_oca.model_iot_device_input"
).id,
"call_function": "test_model_function",
}
)
self.env["iot.device.input"].create(
{
"name": "Multi Input",
"device_id": self.device.id,
"serial": self.device_identification,
"passphrase": self.passphrase,
"call_function": "parse_multi_input",
}
)
self.single_input_values = [{"input": self.address_1, "value": "test"}]
self.values = json.dumps(
[
{"address": self.address_1, "value": "test value 1"},
{
"address": self.address_1,
"value": 2.3,
}, # Checking that nothing wrong happens with a non string
{"address": self.address_2, "value": "test value 3"},
]
)
def test_single_controller(self):
res = self.url_open(
"/iot/%s/action" % self.serial,
data={"passphrase": self.input_passphrase, "value": "123"},
)
self.assertEqual(res.json()["status"], "ok")
def test_single_controller_archived_device(self):
self.device.write({"active": False})
res = self.url_open(
"/iot/%s/action" % self.serial,
data={"passphrase": self.input_passphrase, "value": "123"},
)
self.assertEqual(res.json()["status"], "error")
def test_multi_controller_archived_device(self):
self.device.write({"active": False})
res = self.url_open(
"/iot/%s/multi_input" % self.serial,
data={"passphrase": self.input_passphrase, "values": self.values},
)
self.assertEqual(res.json()["status"], "error")
def test_multi_input_controller_error_passphrase(self):
res = self.url_open(
"/iot/%s/multi_input" % self.device_identification,
data={"values": self.values},
).json()
self.assertEqual(res["status"], "error")
def test_multi_input_controller_error_values(self):
res = self.url_open(
"/iot/%s/multi_input" % self.device_identification,
data={"passphrase": self.passphrase},
).json()
self.assertEqual(res["status"], "error")
def test_multi_input_controller_syntax_error(self):
res = self.url_open(
"/iot/%s/multi_input" % self.device_identification,
data={"passphrase": self.passphrase, "values": "{}"},
).json()
self.assertEqual(res["status"], "error")
def test_multi_input_controller_malformed_error(self):
res = self.url_open(
"/iot/%s/multi_input" % self.device_identification,
data={"passphrase": self.passphrase, "values": "{1234}"},
).json()
self.assertEqual(res["status"], "error")
def test_multi_input_controller(self):
res = self.url_open(
"/iot/%s/multi_input" % self.device_identification,
data={"passphrase": self.passphrase, "values": self.values},
)
result = res.json()
for response in result:
self.assertEqual(response["status"], "ok")
def test_multi_input_controller_unauthorized_iot_exists(self):
res = self.url_open(
"/iot/%s/check" % self.serial, data={"passphrase": self.input_passphrase}
).json()
self.assertEqual(res["state"], True)
def test_multi_input_controller_unauthorized_iot_no_exists(self):
res = self.url_open(
"/iot/%s/check" % self.passphrase,
data={"passphrase": self.input_passphrase},
).json()
self.assertEqual(res["state"], False)

View file

@ -0,0 +1,122 @@
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestIotIn(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.serial = "testingdeviceserial"
cls.passphrase = "password"
cls.system = cls.env["iot.communication.system"].create({"name": "Demo system"})
cls.device = cls.env["iot.device"].create(
{"name": "Device", "communication_system_id": cls.system.id}
)
cls.device_input = cls.env["iot.device.input"].create(
{
"name": "Input",
"device_id": cls.device.id,
"active": True,
"serial": cls.serial,
"passphrase": cls.passphrase,
"call_model_id": cls.env.ref("iot_input_oca.model_iot_device_input").id,
"call_function": "test_input_device",
}
)
cls.iot = cls.env["iot.device.input"]
def test_device_action_count_ids(self):
self.assertEqual(self.device.input_count, 1)
def _get_devices(self):
action = self.device.action_show_input()
devices = self.env[action["res_model"]]
if action["res_id"]:
devices = devices.browse(action["res_id"])
else:
devices = devices.search(action["domain"])
return devices
def test_device_action(self):
devices = self._get_devices()
self.assertEqual(devices, self.device_input)
device_input_02 = self.env["iot.device.input"].create(
{
"name": "Input",
"device_id": self.device.id,
"active": True,
"serial": self.serial + self.serial,
"passphrase": self.passphrase,
"call_model_id": self.env.ref(
"iot_input_oca.model_iot_device_input"
).id,
"call_function": "test_input_device",
}
)
devices = self._get_devices()
self.assertIn(self.device_input, devices)
self.assertIn(device_input_02, devices)
def test_device_error_wrong_serial(self):
self.assertFalse(
self.iot.get_device(
serial=self.serial + self.serial, passphrase=self.passphrase
)
)
def test_device_error_wrong_passphrase(self):
self.assertFalse(
self.iot.get_device(
serial=self.serial, passphrase=self.passphrase + self.passphrase
)
)
def test_device_error_archived(self):
self.device_input.active = False
self.assertFalse(
self.iot.get_device(serial=self.serial, passphrase=self.passphrase)
)
def test_device_error_missing_data(self):
with self.assertRaises(ValidationError):
self.iot.get_device(serial=False, passphrase=self.passphrase)
def test_error_execution_without_device(self):
res = self.iot.call_device(value="hello")
self.assertEqual(res["status"], "error")
def test_device_input_calling(self):
iot = self.iot.get_device(serial=self.serial, passphrase=self.passphrase)
self.assertEqual(iot, self.device_input)
self.assertEqual(0, self.device_input.action_count)
args = "hello"
res = iot.call_device(value=args)
self.assertEqual(res, {"status": "ok", "value": args})
self.assertTrue(self.device_input.action_ids)
self.assertEqual(self.device_input.action_ids.args, str([args]))
self.assertEqual(self.device_input.action_ids.res, str(res))
self.assertEqual(1, self.device_input.action_count)
def test_device_input_calling_with_lang(self):
devices = self._get_devices()
self.assertEqual(devices, self.device_input)
device_input_lang = self.env["iot.device.input"].create(
{
"name": "Input",
"lang": "en_US",
"device_id": self.device.id,
"active": True,
"serial": self.serial + self.serial,
"passphrase": self.passphrase,
"call_model_id": self.env.ref(
"iot_input_oca.model_iot_device_input"
).id,
"call_function": "test_input_device",
}
)
devices = self._get_devices()
self.assertIn(self.device_input, devices)
self.assertIn(device_input_lang, devices)
args = "hello"
res = device_input_lang.call_device(value=args)
self.assertEqual(res, {"status": "ok", "value": args})

View file

@ -0,0 +1,196 @@
from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger
class TestIotIn(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.device_identification = "test_device_name"
cls.passphrase = "password"
cls.system = cls.env["iot.communication.system"].create({"name": "Demo system"})
cls.device = cls.env["iot.device"].create(
{
"name": "Device",
"communication_system_id": cls.system.id,
}
)
cls.address_1 = "I0"
cls.device_input_1 = cls.env["iot.device.input"].create(
{
"name": "Input 1",
"device_id": cls.device.id,
"address": cls.address_1,
"call_model_id": cls.env.ref("iot_input_oca.model_iot_device_input").id,
"call_function": "test_model_function",
}
)
cls.address_2 = "I1"
cls.env["iot.device.input"].create(
{
"name": "Input 2",
"device_id": cls.device.id,
"address": cls.address_2,
"call_model_id": cls.env.ref("iot_input_oca.model_iot_device_input").id,
"call_function": "test_model_function",
}
)
cls.env["iot.device.input"].create(
{
"name": "Multi Input",
"device_id": cls.device.id,
"serial": cls.device_identification,
"passphrase": cls.passphrase,
"call_function": "parse_multi_input",
}
)
cls.single_input_values = [{"input": cls.address_1, "value": "test"}]
cls.iot = cls.env["iot.device.input"]
def test_multi_input_error_wrong_identification(self):
iot = self.iot.get_device(
serial=self.device_identification + self.device_identification,
passphrase=self.passphrase,
)
# device not found -> result is error
self.assertEqual(
iot.call_device(values=self.single_input_values)["status"],
"error",
)
def test_multi_input_error_no_inputs(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
self.assertEqual(
iot.call_device(values=[])["status"],
"ko",
)
def test_multi_input_non_existing_address(self):
non_existing_address = "I3"
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(
values=[{"address": non_existing_address, "value": "test value 1"}],
)["result"]:
self.assertEqual(response["status"], "error")
@mute_logger("odoo.addons.iot_input_oca.models.iot_device_input")
def test_error_missing_parameter(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(values=[{"address": self.address_1}])["result"]:
self.assertEqual(response["status"], "ko")
@mute_logger("odoo.addons.iot_input_oca.models.iot_device_input")
def test_error_with_extra_args(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(
values=[{"address": self.address_1, "uuid": "abc"}],
)["result"]:
self.assertEqual(response["status"], "ko")
self.assertTrue("uuid" in response)
def test_error_no_address_with_extra_args(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(values=[{"uuid": "abc"}])["result"]:
self.assertEqual(response["status"], "error")
self.assertTrue("uuid" in response)
def test_error_no_address(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(values=[{"value": "test value"}])["result"]:
self.assertEqual(response["status"], "error")
def test_correct_one_input(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(
values=[{"address": self.address_1, "value": "test"}],
)["result"]:
self.assertEqual(response["status"], "ok")
def test_correct_two_inputs(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for response in iot.call_device(
values=[
{"address": self.address_1, "value": "test value 1"},
{
"address": self.address_1,
"value": 2.3,
}, # Checking that nothing wrong happens with a non string
{"address": self.address_2, "value": "test value 3"},
],
)["result"]:
self.assertEqual(response["status"], "ok")
def test_correct_with_extra_args(self):
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
response_with_uuid = [
{"address": self.address_1, "value": "test value 1", "uuid": "abc"},
{"address": self.address_1, "value": "test value 2", "uuid": "def"},
{"address": self.address_2, "value": "test value 3", "uuid": "ghi"},
]
for response in iot.call_device(values=response_with_uuid)["result"]:
self.assertTrue(response["uuid"])
self.assertEqual(
response["message"],
[x for x in response_with_uuid if x["uuid"] == response["uuid"]][0][
"value"
],
)
def test_error_archived_device(self):
self.device.active = False
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
self.assertEqual(
iot.call_device(
values=[{"address": self.address_1, "value": "test"}],
)["status"],
"error",
)
def test_error_archived_device_input(self):
self.device_input_1.active = False
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for result in iot.call_device(
values=[{"address": self.address_1, "value": "test"}],
)["result"]:
self.assertEqual(
result["status"],
"error",
)
def test_error_archived_device_input_extra_args(self):
self.device_input_1.active = False
iot = self.iot.get_device(
serial=self.device_identification, passphrase=self.passphrase
)
for result in iot.call_device(
values=[{"address": self.address_1, "value": "test", "uuid": "ghi"}],
)["result"]:
self.assertEqual(
result["status"],
"error",
)
self.assertEqual(result["uuid"], "ghi")

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="iot_device_input_tree" model="ir.ui.view">
<field name="name">iot.device.input.tree</field>
<field name="model">iot.device.input</field>
<field name="arch" type="xml">
<tree delete="0">
<field name="name" />
<field name="address" />
<field name="serial" />
</tree>
</field>
</record>
<record id="iot_device_input_form" model="ir.ui.view">
<field name="name">iot.device.input.form</field>
<field name="model">iot.device.input</field>
<field name="arch" type="xml">
<form>
<header />
<sheet>
<widget
name="web_ribbon"
text="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"
/>
<field name="active" invisible="1" />
<div class="oe_button_box" name="button_box" />
<div class="oe_title">
<h1>
<field name="name" />
</h1>
</div>
<group>
<group>
<field name="address" />
<field name="serial" />
<field name="passphrase" widget="password" />
</group>
<group>
<field name="call_model_id" options="{'no_create':True}" />
<field name="call_function" />
<field name="lang" />
</group>
</group>
<notebook invisible="1" />
</sheet>
</form>
</field>
</record>
<record id="iot_device_input_search" model="ir.ui.view">
<field name="name">iot.device.input.search</field>
<field name="model">iot.device.input</field>
<field name="arch" type="xml">
<search string="IoT Device Input Search">
<field name="name" />
<filter
name="active"
string="Active"
domain="[('active','=',True)]"
help="Active"
/>
<filter
name="inactive"
string="Inactive"
domain="[('active','=',False)]"
help="Inactive"
/>
<separator />
</search>
</field>
</record>
<record model="ir.actions.act_window" id="iot_device_input_action">
<field name="name">IoT Inputs</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">iot.device.input</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="iot_device_form" model="ir.ui.view">
<field name="name">iot.device.form</field>
<field name="model">iot.device</field>
<field name="inherit_id" ref="iot_oca.iot_device_form" />
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button
name="action_show_input"
type="object"
class="oe_stat_button"
icon="fa-keyboard-o"
>
<field string="Inputs" name="input_count" widget="statinfo" />
</button>
</xpath>
</field>
</record>
<record id="iot_device_kanban" model="ir.ui.view">
<field name="name">iot.device.kanban</field>
<field name="model">iot.device</field>
<field name="inherit_id" ref="iot_oca.iot_device_kanban" />
<field name="arch" type="xml">
<xpath expr="//div[@role='menu']/*[1]" position="before">
<a
type="object"
name="action_show_input"
role="menuitem"
class="dropdown-item"
>
<i class="fa fa-keyboard-o" />
Inputs
</a>
</xpath>
</field>
</record>
</odoo>