From d9c178f2529d21ea137aa8c4397e343f46f4339e Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Fri, 6 Mar 2020 12:06:07 +0100 Subject: [PATCH 01/31] [12.0][ADD] iot_input --- iot_input_oca/README.rst | 110 +++++ iot_input_oca/__init__.py | 2 + iot_input_oca/__manifest__.py | 22 + iot_input_oca/controller/__init__.py | 1 + .../controller/iot_input_controller.py | 30 ++ iot_input_oca/i18n/iot_input.pot | 171 +++++++ iot_input_oca/models/__init__.py | 3 + iot_input_oca/models/iot_device.py | 32 ++ iot_input_oca/models/iot_device_input.py | 83 ++++ iot_input_oca/models/mail_message.py | 16 + iot_input_oca/readme/CONTRIBUTORS.rst | 1 + iot_input_oca/readme/DESCRIPTION.rst | 14 + iot_input_oca/readme/USAGE.rst | 12 + iot_input_oca/security/ir.model.access.csv | 5 + iot_input_oca/static/description/icon.png | Bin 0 -> 4151 bytes iot_input_oca/static/description/index.html | 449 ++++++++++++++++++ iot_input_oca/tests/__init__.py | 1 + iot_input_oca/tests/test_iot_in.py | 32 ++ .../views/iot_device_input_views.xml | 53 +++ iot_input_oca/views/iot_device_views.xml | 21 + 20 files changed, 1058 insertions(+) create mode 100644 iot_input_oca/README.rst create mode 100644 iot_input_oca/__init__.py create mode 100644 iot_input_oca/__manifest__.py create mode 100644 iot_input_oca/controller/__init__.py create mode 100644 iot_input_oca/controller/iot_input_controller.py create mode 100644 iot_input_oca/i18n/iot_input.pot create mode 100644 iot_input_oca/models/__init__.py create mode 100644 iot_input_oca/models/iot_device.py create mode 100644 iot_input_oca/models/iot_device_input.py create mode 100644 iot_input_oca/models/mail_message.py create mode 100644 iot_input_oca/readme/CONTRIBUTORS.rst create mode 100644 iot_input_oca/readme/DESCRIPTION.rst create mode 100644 iot_input_oca/readme/USAGE.rst create mode 100644 iot_input_oca/security/ir.model.access.csv create mode 100644 iot_input_oca/static/description/icon.png create mode 100644 iot_input_oca/static/description/index.html create mode 100644 iot_input_oca/tests/__init__.py create mode 100644 iot_input_oca/tests/test_iot_in.py create mode 100644 iot_input_oca/views/iot_device_input_views.xml create mode 100644 iot_input_oca/views/iot_device_views.xml diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst new file mode 100644 index 00000000..bf89d639 --- /dev/null +++ b/iot_input_oca/README.rst @@ -0,0 +1,110 @@ +========= +IoT Input +========= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/12.0/iot_input + :alt: OCA/iot +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/iot-12-0/iot-12-0-iot_input + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/269/12.0 + :alt: Try me on Runbot + +|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 +===== + +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. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Creu Blanca + +Contributors +~~~~~~~~~~~~ + +* Enric Tobella + +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 `__: + +|maintainer-etobella| + +This module is part of the `OCA/iot `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/iot_input_oca/__init__.py b/iot_input_oca/__init__.py new file mode 100644 index 00000000..5607426d --- /dev/null +++ b/iot_input_oca/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import controller diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py new file mode 100644 index 00000000..54ff9d9b --- /dev/null +++ b/iot_input_oca/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2018 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + 'name': 'IoT Input', + 'version': '12.0.1.0.0', + 'category': 'IoT', + 'author': "Creu Blanca, " + "Odoo Community Association (OCA)", + 'license': 'AGPL-3', + 'installable': True, + 'summary': 'IoT Input module', + 'depends': [ + 'iot_output', + 'mail', + ], + 'maintainers': ['etobella'], + 'data': [ + 'security/ir.model.access.csv', + 'views/iot_device_views.xml', + 'views/iot_device_input_views.xml', + ], +} diff --git a/iot_input_oca/controller/__init__.py b/iot_input_oca/controller/__init__.py new file mode 100644 index 00000000..c204f049 --- /dev/null +++ b/iot_input_oca/controller/__init__.py @@ -0,0 +1 @@ +from . import iot_input_controller diff --git a/iot_input_oca/controller/iot_input_controller.py b/iot_input_oca/controller/iot_input_controller.py new file mode 100644 index 00000000..7e085e76 --- /dev/null +++ b/iot_input_oca/controller/iot_input_controller.py @@ -0,0 +1,30 @@ +# Copyright 2018 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import json +from odoo import http + + +class CallIot(http.Controller): + @http.route([ + '/iot//action', + ], type='http', auth="none", methods=['POST'], csrf=False) + def call_unauthorized_iot(self, serial, *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, kwargs['passphrase']).call_device(kwargs['value'])) + + @http.route([ + '/iot//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}) diff --git a/iot_input_oca/i18n/iot_input.pot b/iot_input_oca/i18n/iot_input.pot new file mode 100644 index 00000000..ea768a32 --- /dev/null +++ b/iot_input_oca/i18n/iot_input.pot @@ -0,0 +1,171 @@ +# 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_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:58 +#, 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 +#: 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: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: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 +#: 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:44 +#, python-format +msgid "Serial and passphrase are required" +msgstr "" + diff --git a/iot_input_oca/models/__init__.py b/iot_input_oca/models/__init__.py new file mode 100644 index 00000000..58626c86 --- /dev/null +++ b/iot_input_oca/models/__init__.py @@ -0,0 +1,3 @@ +from . import mail_message +from . import iot_device +from . import iot_device_input diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py new file mode 100644 index 00000000..527bce41 --- /dev/null +++ b/iot_input_oca/models/iot_device.py @@ -0,0 +1,32 @@ +from odoo import api, fields, models + + +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) + + @api.multi + def action_show_input(self): + self.ensure_one() + action = self.env.ref('iot_input.iot_device_input_action') + result = action.read()[0] + + result['context'] = { + 'default_device_id': self.id, + } + result['domain'] = "[('device_id', '=', " + \ + str(self.id) + ")]" + if len(self.input_ids) == 1: + result['views'] = [(False, 'form')] + result['res_id'] = self.input_ids.id + return result diff --git a/iot_input_oca/models/iot_device_input.py b/iot_input_oca/models/iot_device_input.py new file mode 100644 index 00000000..2e9dbd6f --- /dev/null +++ b/iot_input_oca/models/iot_device_input.py @@ -0,0 +1,83 @@ +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class IotDeviceInput(models.Model): + _name = 'iot.device.input' + _description = "Device input" + + name = fields.Char(required=True) + device_id = fields.Many2one('iot.device', required=True, readonly=True) + call_model_id = fields.Many2one('ir.model') + call_function = fields.Char(required=True) + serial = 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, value): + 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)(value) + + def parse_args(self, serial, passphrase): + if not serial or not passphrase: + raise ValidationError(_('Serial and passphrase are required')) + return [('serial', '=', serial), ('passphrase', '=', passphrase)] + + @api.model + def get_device(self, serial, passphrase): + return self.search(self.parse_args(serial, passphrase), limit=1) + + @api.model + def get_auth_device(self, serial): + return self.search([('serial', '=', serial)], limit=1) + + @api.multi + def call_device(self, value): + if not self: + return {'status': 'error', 'message': _('Device cannot be found')} + else: + res = self._call_device(value) + res['status'] = 'ok' + self.env['iot.device.input.action'].create( + self._add_action_vals(value, res)) + return res + + def _add_action_vals(self, value, res): + return { + 'input_id': self.id, + 'args': str(value), + 'res': str(res), + } + + def test_input_device(self, value): + return {'value': value} + + +class IoTDeviceAction(models.Model): + _name = 'iot.device.input.action' + _description = 'Action of device inputs' + + input_id = fields.Many2one('iot.device.input') + args = fields.Char() + res = fields.Char() diff --git a/iot_input_oca/models/mail_message.py b/iot_input_oca/models/mail_message.py new file mode 100644 index 00000000..e0d47b4b --- /dev/null +++ b/iot_input_oca/models/mail_message.py @@ -0,0 +1,16 @@ +from odoo import api, models, _ + + +class MailMessage(models.Model): + _inherit = 'mail.message' + + @api.model + def create(self, vals): + device = self.env.context.get('iot_device_name', False) + if device: + body = vals.get('body', '') + if len(body) > 0: + body += '
' + vals['body'] = '%s%s' % ( + body, _('Detected automatically by %s') % device) + return super().create(vals) diff --git a/iot_input_oca/readme/CONTRIBUTORS.rst b/iot_input_oca/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..93ec993e --- /dev/null +++ b/iot_input_oca/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Enric Tobella diff --git a/iot_input_oca/readme/DESCRIPTION.rst b/iot_input_oca/readme/DESCRIPTION.rst new file mode 100644 index 00000000..0ca60637 --- /dev/null +++ b/iot_input_oca/readme/DESCRIPTION.rst @@ -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 diff --git a/iot_input_oca/readme/USAGE.rst b/iot_input_oca/readme/USAGE.rst new file mode 100644 index 00000000..3dbd5bc9 --- /dev/null +++ b/iot_input_oca/readme/USAGE.rst @@ -0,0 +1,12 @@ +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. diff --git a/iot_input_oca/security/ir.model.access.csv b/iot_input_oca/security/ir.model.access.csv new file mode 100644 index 00000000..ee3e9c5d --- /dev/null +++ b/iot_input_oca/security/ir.model.access.csv @@ -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.group_iot_user,1,1,1,0 +manage_iot_device_input,access_iot_device_input,model_iot_device_input,iot.group_iot_manager,1,1,1,1 +access_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot.group_iot_user,1,1,1,0 +manage_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot.group_iot_manager,1,1,1,1 diff --git a/iot_input_oca/static/description/icon.png b/iot_input_oca/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..da43f6f07766d54a65259a14a0688ace6b65ccf0 GIT binary patch literal 4151 zcmZWsXH-*76TUzYLYH2pNmZH%p@RqnrArY(2u0}~r3(S+Em4Zn1Of^Q0hAJ?1O!Zi zRO#|kLJ^P}ic05;zrVA0XYbCrb7%JK%(MHXn43Zw>3Hb?0ARdhsCSP%!vA&JOJv!t z<=jUeF1Z*%^?-|it)#soi>v_$7(NIlTTK4z6uOcHVPqxElRGB*G>bH>G{V;(IcZb^ z0CUeBy<1jc(_0Rnw(R#Oq6?luA5KAT$qQLAE5RL@rgC?XeoW$vPvVUB|b9kZT&QO9;WeR z60P{&jv~|Mw*1Tl zV-eyjx06?FTmHQ#Mv_smC~6z=6(aaBUP0-3_n4_rQumh;g?bj{F+tad2A#b@^644r z7bJmHR7q_uv)^q-+41GF@{g=E{zV4&F|Xw-1}KyHG^s|P;hZOuX%jM+FpVh3sdVO{ z&098KYvVP2+2F?8bTS=86rX_mrQNU3xo}u_$oEx`?o4)N^dmu(!5YROM-Gaf2m2XF2 za-aFkf~%g;mB^95oj2VXd{~S5waJ;4Aml)a)Yk&I`FIpqU*>Uhzc5EKQD`8d0Lk{4 zS0S!ydb-&fl~=31>;O3tLErB}78@lgAe=x0TE5=v%X)CIX7W3vKCtt{$NkQqkdo$)aq{SD8uQ#!$HJDV zOS4uGQ5+8s_af{hg#-L#!EBtX8cFsX}x%**redz6}R%hK7`C6+!k2)sYU23PB)f!o~T z`$QkC(BI1_7kMo26;M|txROzrzWI$(V^b){V2D;{cKI*LXeOb*YW2Ic$89ST=q!#YnL|6u<(?RDI=~L?4*xt zJ#LNc#cKBdxwJt6$G|@c2nRE88#;lppCPiwjGQVO6oS^Lm$Eg9BDGEIlhX9&C&|!a z;Gj&SyhSHkE|Gyde#t&dK_Q^}?vkW^l$Wbl3MTHI>o(yIZOCs+zalG#^mJ68%JF{) zV%oIQb$H;QTAt=dwFoI}@_h9O_fHL3mwOPDRVF``ySIHc81XfASao>P(oC9PtP~lv zuO5|G^g*Gvq@EIhznV!DmJy~F)kv(mnYr7t8kzMwi_>*9Tg*!oD<^#Qp+>yGE9NR~ zhOywrX;c-ZN5oiMc7Iu&yb`pMb-^Xc7SzZ1slfJ7Jz{AYC1A^~VqNwu<3J_iHIXOY zaL0*#Y}UXvQgIhZ6%i2v;kAttXLXL~pxesho&J+idBu2;-okKO25-Udq5Vrnrq43j zsI@OMm(Y@{?M3!EqXxeNtXZH4W}jJ7%h~G)i$9}2S&8a5geYoeUYR2m!2b*~E!%Lh zQAnyq-l%;84Y#I#hbUs8dhT9OKCT&&+;a_TF&1DZew3oP$b@Mh2NDn*Bk?-EVpKEKb?MS=e^e|edw;1SV- zkJ-+Z=aLPfCk>$#Jrve9_xGO)f3)RR%W6d2B&UHnE8XM{*T@FNpJ*gJCzz}1Yw~h> zck+CD%6Y51Gf4CPwSY^1ifUG_Hg?T!X^+^geb_APj9h(~5Xz9_2)c6eq;{G>^UrW; zsv`1%KDI$WUdh$f)+`!vZ4%Ebwk~{-U3B!}{9t-jT0Kaa?4*--4{fg!=8n@vr}){# z55{J^f9pog0+F#pD|X14kzeuy_r%71lheX(Uvs+{btIxoe&w_MJ9I+Y>K&I7H^bc9 zb?NV#Aem#i{Y?u?pGNWrLrq5tfeBnqwtBxMb(8Y*kIErpWy|XSsR{MSnQwqtHrHv$ zYaO6<`f>d@RdzgDmYP5l5yaTYv7|}4d|or-&yc62m74qGqJe7->v+5Gb9yd~Mi!eY zZW88AO-ik=o$28GwnZV1V0vDIsx34W4E0Ah;_-tHX9#%bg6PwirREn<3~~Aaf&vleV=1V`F~UY} z5>Uv~Ic3sjZCBYyNvM(;H)anYK9Tk{7!I$&c3L5BKPB2dj&%beU*{Y5EhgjrbzQt} zltDh`PQnWpqtK$-m=@d82KfZgurRC3*|`8Ox>l-6IQmI{24uO)(_dneRrsJ?JDNmE*!&YM^7n;+lx8n#uRPKiU9-*&09KKZ8 zT=4c__w2(hJvo#_M`m@oB`JvKIO&3qhgW1q8${l#X8Yiayrt+`NvM4i@Z!tm>bj+} zEEv(eS2YK>cK?dbTqa5^2cxi#mXeF|kvBP?J7vhh3!9)Gm5^hbaYMW~IwE^KbnEt; zo&>S$JNGV_SqGh*nF1+Q$}T49i&e|yBW$Af+qMEXaVsgN`iFu26QrdLe4HmmlD$$+ zHR)z*Hq|9(*`c%3tmZJE=*SFQ8->2b;U+AS^p_9+$VOR;zQ}~mL7<)e>-z`NFJO*O znaem$!WaHF3I3oT3NJOhdtrxeO=Q;>mOAqe!|8j(M-?3a>t3Ag5?exAr+9ZdL3dYG zAaHbLVIV~@JNo7_`>Lqs#`VlXb!x2D;Y_}P2wXcMR2q}E3K0$IlYV%onC8053jXt$-+-LZGm_uB2XpvH3vnFM4n`r)Oq@QB2{<>$4$-oEG&ZTt2R*~aT4>6;raIk`{2`?g2je`F-#Ly$ z@^efpEX(XaEqLp5`jGZkuwu6ePsdQ?2ve6_h=_3UpguACKF-z6_UiTiex6qRI>XMB zgeW@@$&LWp43D`+rVC_kg>2Cm7zTZ-qB#p`h5=Sg^1)Qk+)yUFt_r!^hXws0#JMRJ zM@=#~^v>ToelN2iK;Jvr47^@%#K?xLhX~9w+r;TFds_k9OtKA_TyHKqmSz>YzZ+HH zBjco4GKdmgRt>8Z$d|DIULP}p`*UDs)8WnL#%O|RAlD^ZyUTk&gn;={#|A!EKd*N| zf6QV;U}cnRtZ82s0z4p<^;Kyv_Ps=pcsa*CDCL3L>F6CO8Ws@2*{HKOj*zX43;12Ai zzkDCSM?PU7hPsBXj^IxoN-J)=wUv=mhW{eW7u>b@)}FQkjhasX?3j)3r!+U}og{Nd zVnMxUL%(5)UfftQwj0BRti+hwKvTwwf>n#9)bbh}eQ0ziHzG!{x%e*kF$o_ixG*>~3u9l8#5|U3pJfJbO z%N)wZ&CC7aasM^y4q{n3$Z9N*955Hq(awRX+KI*c<9bR0$uvz`X6jG5fZoF{uLinl z+M{V9prk@+rtxAKb$m;+{GOC!5Z}Ak$0-rhg`IpL3Lqcq79CCh$ zT8AJ(DYVQ+!LpYE&>r2q-V6%_@Du6CdFEakfGYDN1#!gESokOSMDU28=|F=9?&>)s v*XR!b{Fb+Wh!6vS_f{D9Xl*e;;G7=(E>>ZMBDIA~@qs(~rg}BHPI3POT<6QK literal 0 HcmV?d00001 diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html new file mode 100644 index 00000000..bde85965 --- /dev/null +++ b/iot_input_oca/static/description/index.html @@ -0,0 +1,449 @@ + + + + + + +IoT Input + + + +
+

IoT Input

+ + +

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

+

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

+ +
+

Usage

+
    +
  1. Create a Device on IoT > Config Devices
  2. +
  3. Access the Inputs section of the device
  4. +
  5. Create an input. You must define a serial, passphrase, function and model
  6. +
+

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.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Creu Blanca
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainer:

+

etobella

+

This module is part of the OCA/iot project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/iot_input_oca/tests/__init__.py b/iot_input_oca/tests/__init__.py new file mode 100644 index 00000000..5ec21d93 --- /dev/null +++ b/iot_input_oca/tests/__init__.py @@ -0,0 +1 @@ +from . import test_iot_in diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py new file mode 100644 index 00000000..813ad4d5 --- /dev/null +++ b/iot_input_oca/tests/test_iot_in.py @@ -0,0 +1,32 @@ +from odoo.tests.common import TransactionCase + + +class TestIotIn(TransactionCase): + def test_device(self): + serial = 'testingdeviceserial' + passphrase = 'password' + device = self.env['iot.device'].create({ + 'name': 'Device', + }) + input = self.env['iot.device.input'].create({ + 'name': 'Input', + 'device_id': device.id, + 'serial': serial, + 'passphrase': passphrase, + 'call_model_id': self.ref('iot_input.model_iot_device_input'), + 'call_function': 'test_input_device' + }) + iot = self.env['iot.device.input'] + self.assertFalse( + iot.get_device(serial=serial + serial, passphrase=passphrase)) + self.assertFalse( + iot.get_device(serial=serial, passphrase=passphrase + passphrase)) + iot = iot.get_device( + serial=serial, passphrase=passphrase) + self.assertEqual(iot, input) + args = 'hello' + res = iot.call_device(args) + self.assertEqual(res, {'status': 'ok', 'value': args}) + self.assertTrue(input.action_ids) + self.assertEqual(input.action_ids.args, str(args)) + self.assertEqual(input.action_ids.res, str(res)) diff --git a/iot_input_oca/views/iot_device_input_views.xml b/iot_input_oca/views/iot_device_input_views.xml new file mode 100644 index 00000000..84fe0c58 --- /dev/null +++ b/iot_input_oca/views/iot_device_input_views.xml @@ -0,0 +1,53 @@ + + + + + iot.device.input.tree + iot.device.input + + + + + + + + + + iot.device.input.form + iot.device.input + +
+
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + IoT Inputs + ir.actions.act_window + iot.device.input + form + tree,form + + + diff --git a/iot_input_oca/views/iot_device_views.xml b/iot_input_oca/views/iot_device_views.xml new file mode 100644 index 00000000..0985c6ce --- /dev/null +++ b/iot_input_oca/views/iot_device_views.xml @@ -0,0 +1,21 @@ + + + + + iot.device.form + iot.device + + + + + + + + + From 3b31ae4bf35016832ed0c2cc8a89f64c920a16fd Mon Sep 17 00:00:00 2001 From: "Dimitrios T. Tanis" Date: Sat, 25 Jul 2020 00:52:56 +0300 Subject: [PATCH 02/31] [UPD] Adds new fields, multi_input controller, views Adds active field in device, input Adds device_identification and passphrase in device Adds address field in input Adds new controller that can take multi event and/or multi input data Updates tests [FIX] Don't remove existing users from security group Updating the module removed existing users from Manager group. This changes behaviour so that users that are already in this group are not removed. --- iot_input_oca/README.rst | 38 ++++++ iot_input_oca/__manifest__.py | 2 +- .../controller/iot_input_controller.py | 54 +++++++- iot_input_oca/i18n/iot_input.pot | 82 +++++++++++- iot_input_oca/models/iot_device.py | 100 ++++++++++++++- iot_input_oca/models/iot_device_input.py | 7 ++ iot_input_oca/readme/CONTRIBUTORS.rst | 1 + iot_input_oca/readme/USAGE.rst | 37 ++++++ iot_input_oca/static/description/index.html | 30 +++++ iot_input_oca/tests/test_iot_in.py | 118 +++++++++++++++++- .../views/iot_device_input_views.xml | 22 +++- 11 files changed, 478 insertions(+), 13 deletions(-) diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index bf89d639..fe9af15d 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -48,6 +48,12 @@ Examples: Usage ===== +There are two endpoints you can use: +Endpoint 1: /iot//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 @@ -61,6 +67,37 @@ The function that the system will call must be of the following kind:: 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//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 and array of values for input + +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 return 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 =========== @@ -83,6 +120,7 @@ Contributors ~~~~~~~~~~~~ * Enric Tobella +* Dimitrios Tanis Maintainers ~~~~~~~~~~~ diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 54ff9d9b..99d7376f 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { 'name': 'IoT Input', - 'version': '12.0.1.0.0', + 'version': '12.0.1.1.0', 'category': 'IoT', 'author': "Creu Blanca, " "Odoo Community Association (OCA)", diff --git a/iot_input_oca/controller/iot_input_controller.py b/iot_input_oca/controller/iot_input_controller.py index 7e085e76..bf23778f 100644 --- a/iot_input_oca/controller/iot_input_controller.py +++ b/iot_input_oca/controller/iot_input_controller.py @@ -2,13 +2,16 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import json -from odoo import http +import logging +from odoo import http, _ + +_logger = logging.getLogger(__name__) class CallIot(http.Controller): @http.route([ '/iot//action', - ], type='http', auth="none", methods=['POST'], csrf=False) + ], type='http', auth="none", methods=['POST'], csrf=False) def call_unauthorized_iot(self, serial, *args, **kwargs): request = http.request if not request.env: @@ -16,9 +19,54 @@ def call_unauthorized_iot(self, serial, *args, **kwargs): return json.dumps(request.env['iot.device.input'].sudo().get_device( serial, kwargs['passphrase']).call_device(kwargs['value'])) + @http.route([ + '/iot//multi_input', + ], type='http', auth="none", methods=['POST'], csrf=False) + def call_unauthorized_iot_multi_input( + self, device_identification, *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 'passphrase' not in kwargs: + _logger.warning('Passphrase is required') + return json.dumps({'status': 'error', + 'message': _('Passphrase is required')}) + if 'values' not in kwargs: + _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: + values = json.loads(kwargs['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 + return json.dumps( + request.env['iot.device'].sudo().parse_multi_input( + device_identification, kwargs['passphrase'], values)) + @http.route([ '/iot//check', - ], type='http', auth="none", methods=['POST'], csrf=False) + ], type='http', auth="none", methods=['POST'], csrf=False) def check_unauthorized_iot(self, serial, *args, **kwargs): request = http.request if not request.env: diff --git a/iot_input_oca/i18n/iot_input.pot b/iot_input_oca/i18n/iot_input.pot index ea768a32..08f0b158 100644 --- a/iot_input_oca/i18n/iot_input.pot +++ b/iot_input_oca/i18n/iot_input.pot @@ -28,6 +28,23 @@ msgstr "" 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" @@ -67,7 +84,7 @@ msgid "Device" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device_input.py:58 +#: code:addons/iot_input/models/iot_device_input.py:60 #, python-format msgid "Device cannot be found" msgstr "" @@ -83,12 +100,23 @@ msgstr "" msgid "Display Name" msgstr "" +#. module: iot_input +#: code:addons/iot_input/models/iot_device.py:126 +#, 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 @@ -110,6 +138,11 @@ msgstr "" 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" @@ -153,6 +186,12 @@ msgstr "" 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" @@ -164,8 +203,47 @@ msgid "Serial" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device_input.py:44 +#: code:addons/iot_input/models/iot_device_input.py:46 #, 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:77 +#: code:addons/iot_input/models/iot_device.py:107 +#: code:addons/iot_input/models/iot_device.py:113 +#: code:addons/iot_input/models/iot_device.py:119 +#, 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 "" + diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py index 527bce41..3d6a7d06 100644 --- a/iot_input_oca/models/iot_device.py +++ b/iot_input_oca/models/iot_device.py @@ -1,4 +1,8 @@ -from odoo import api, fields, models +import logging + +from odoo import api, fields, models, _ + +_logger = logging.getLogger(__name__) class IotDevice(models.Model): @@ -30,3 +34,97 @@ def action_show_input(self): result['views'] = [(False, 'form')] result['res_id'] = self.input_ids.id return result + + @api.multi + def parse_single_input(self, value): + '''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 + ''' + if 'address' not in value.keys(): + _logger.warning('Address for Input is required') + msg = {'status': 'error', + 'message': _('Address for Input is required')} + if 'uuid' in value.keys(): + msg['uuid'] = value['uuid'] + return msg + if 'value' not in value.keys(): + _logger.warning('Value for Input is required') + msg = {'status': 'error', + 'message': _('Value for Input is required')} + if 'uuid' in value.keys(): + msg['uuid'] = value['uuid'] + return msg + + device_input = self.input_ids.filtered(lambda i: i.address == value['address']) + if len(device_input) == 1: + res = device_input._call_device(value) + self.env['iot.device.input.action'].create( + device_input._add_action_vals(value, res)) + if 'uuid' in value: + res['uuid'] = value['uuid'] + return res + else: + _logger.warning('Input with address %s not found', value['address']) + msg = {'status': 'error', + 'message': _('Server Error. Check server logs')} + if 'uuid' in value: + msg['uuid'] = value['uuid'] + return msg + + @api.model + def parse_multi_input(self, device_identification, passphrase, values): + '''Handle multiple inputs for device + + :param string device_identification: + Device identification. + :param string passphrase: + Device passphrase. + :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.with_context( + active_test=False).search( + [('device_identification', '=', device_identification)]) + if not device: + _logger.warning( + 'Device with identification %s not found', + device_identification) + return {'status': 'error', + 'message': _('Server Error. Check server logs')} + if not device.active: + _logger.warning( + 'Device with identification %s is inactive, no data will be logged', + device.device_identification) + return {'status': 'error', + 'message': _('Server Error. Check server logs')} + if device.passphrase != passphrase: + _logger.warning( + 'Wrong passphrase for device with identification %s', + device.device_identification) + return {'status': 'error', + 'message': _('Server Error. Check server logs')} + + if not values: + _logger.warning( + 'Empty values array for device with identification %s', + device.device_identification) + return {'status': 'error', + 'message': _('Empty values array')} + res = [] + for d in values: + res.append(device.parse_single_input(d)) + return res diff --git a/iot_input_oca/models/iot_device_input.py b/iot_input_oca/models/iot_device_input.py index 2e9dbd6f..75749d36 100644 --- a/iot_input_oca/models/iot_device_input.py +++ b/iot_input_oca/models/iot_device_input.py @@ -10,7 +10,9 @@ class IotDeviceInput(models.Model): device_id = fields.Many2one('iot.device', required=True, readonly=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, @@ -73,6 +75,11 @@ def _add_action_vals(self, value, res): def test_input_device(self, value): return {'value': value} + def test_model_function(self, value): + return {'status': 'ok', + 'message': value + } + class IoTDeviceAction(models.Model): _name = 'iot.device.input.action' diff --git a/iot_input_oca/readme/CONTRIBUTORS.rst b/iot_input_oca/readme/CONTRIBUTORS.rst index 93ec993e..61fe3232 100644 --- a/iot_input_oca/readme/CONTRIBUTORS.rst +++ b/iot_input_oca/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Enric Tobella +* Dimitrios Tanis diff --git a/iot_input_oca/readme/USAGE.rst b/iot_input_oca/readme/USAGE.rst index 3dbd5bc9..5412cef4 100644 --- a/iot_input_oca/readme/USAGE.rst +++ b/iot_input_oca/readme/USAGE.rst @@ -1,3 +1,9 @@ +There are two endpoints you can use: +Endpoint 1: /iot//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 @@ -10,3 +16,34 @@ The function that the system will call must be of the following kind:: 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//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 and array of values for input + +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 return 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. diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index bde85965..bc4ae2f3 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -395,6 +395,10 @@

IoT Input

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. @@ -408,6 +412,31 @@

    Usage

    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 and array of values for input

    +

    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 return 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

@@ -429,6 +458,7 @@

Authors

Contributors

diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index 813ad4d5..0681bd95 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -8,9 +8,10 @@ def test_device(self): device = self.env['iot.device'].create({ 'name': 'Device', }) - input = self.env['iot.device.input'].create({ + device_input = self.env['iot.device.input'].create({ 'name': 'Input', 'device_id': device.id, + 'active': True, 'serial': serial, 'passphrase': passphrase, 'call_model_id': self.ref('iot_input.model_iot_device_input'), @@ -23,10 +24,117 @@ def test_device(self): iot.get_device(serial=serial, passphrase=passphrase + passphrase)) iot = iot.get_device( serial=serial, passphrase=passphrase) - self.assertEqual(iot, input) + self.assertEqual(iot, device_input) args = 'hello' res = iot.call_device(args) self.assertEqual(res, {'status': 'ok', 'value': args}) - self.assertTrue(input.action_ids) - self.assertEqual(input.action_ids.args, str(args)) - self.assertEqual(input.action_ids.res, str(res)) + self.assertTrue(device_input.action_ids) + self.assertEqual(device_input.action_ids.args, str(args)) + self.assertEqual(device_input.action_ids.res, str(res)) + + def test_multi_input(self): + device_identification = 'test_device_name' + passphrase = 'password' + device = self.env['iot.device'].create({ + 'name': 'Device', + 'device_identification': device_identification, + 'passphrase': passphrase + }) + address_1 = 'I0' + self.env['iot.device.input'].create({ + 'name': 'Input 1', + 'device_id': device.id, + 'address': address_1, + 'call_model_id': self.ref('iot_input.model_iot_device_input'), + 'call_function': 'test_model_function' + }) + address_2 = 'I1' + self.env['iot.device.input'].create({ + 'name': 'Input 2', + 'device_id': device.id, + 'address': address_2, + 'call_model_id': self.ref('iot_input.model_iot_device_input'), + 'call_function': 'test_model_function' + }) + single_input_values = [{'input': address_1, 'value': 'test'}] + self.assertEqual(device.parse_multi_input( + device_identification + device_identification, passphrase, + single_input_values)['status'], 'error') + self.assertEqual(device.parse_multi_input( + device_identification, passphrase + passphrase, + single_input_values)['status'], 'error') + self.assertEqual(device.parse_multi_input( + device_identification, passphrase, False)['status'], 'error') + + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1}]): + self.assertEqual(response['status'], 'error') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'uuid': 'abc'}]): + self.assertEqual(response['status'], 'error') + self.assertTrue('uuid' in response) + + for response in device.parse_multi_input( + device_identification, passphrase, + [{'value': 'test value'}]): + self.assertEqual(response['status'], 'error') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'value': 'test value', 'uuid': 'abc'}]): + self.assertEqual(response['status'], 'error') + self.assertTrue('uuid' in response) + + non_existing_address = 'I3' + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': non_existing_address, + 'value': 'test value 1'}]): + self.assertEqual(response['status'], 'error') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': non_existing_address, + 'value': 'test value 1', + 'uuid': 'abc'}]): + self.assertEqual(response['status'], 'error') + self.assertTrue('uuid' in response) + + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'value': 'test'}]): + self.assertEqual(response['status'], 'ok') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'value': 'test value 1'}, + {'address': address_1, 'value': 'test value 2'}]): + self.assertEqual(response['status'], 'ok') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'value': 'test value 1'}, + {'address': address_2, 'value': 'test value 2'}]): + self.assertEqual(response['status'], 'ok') + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'value': 'test value 1'}, + {'address': address_1, 'value': 'test value 2'}, + {'address': address_2, 'value': 'test value 3'}]): + self.assertEqual(response['status'], 'ok') + response_with_uuid = [ + {'address': address_1, 'value': 'test value 1', 'uuid': 'abc'}, + {'address': address_1, 'value': 'test value 2', 'uuid': 'def'}, + {'address': address_2, 'value': 'test value 3', 'uuid': 'ghi'} + ] + for response in device.parse_multi_input( + device_identification, passphrase, + response_with_uuid): + self.assertTrue(response['uuid']) + self.assertEqual( + response['message'], + [x for x in response_with_uuid if x['uuid'] == response['uuid']][0] + ) + + device.active = False + self.assertEqual(device.parse_multi_input( + device_identification, passphrase, + [{'address': address_1, 'value': 'test'}])['status'], 'error') diff --git a/iot_input_oca/views/iot_device_input_views.xml b/iot_input_oca/views/iot_device_input_views.xml index 84fe0c58..342521e1 100644 --- a/iot_input_oca/views/iot_device_input_views.xml +++ b/iot_input_oca/views/iot_device_input_views.xml @@ -7,6 +7,7 @@ + @@ -19,7 +20,13 @@
-
+
+ +

@@ -27,6 +34,7 @@

+ @@ -42,6 +50,18 @@ + + iot.device.input.search + iot.device.input + + + + + + + + + IoT Inputs ir.actions.act_window From ed77af4c1851dd72a86c257d4579954253d2fb55 Mon Sep 17 00:00:00 2001 From: "Dimitrios T. Tanis" Date: Sat, 26 Sep 2020 21:14:56 +0300 Subject: [PATCH 03/31] [FIX][iot_input] Allow passing number as address In memory restricted devices (e.g. arduinos et all) sending the input address as number instead of string in the JSON object can save precious memory bytes. This patch allows passing address as number in the JSON object and converting it to string when parsing. --- iot_input_oca/README.rst | 10 ++++++++-- iot_input_oca/__manifest__.py | 2 +- .../examples/multi_input_values.json | 19 +++++++++++++++++++ iot_input_oca/i18n/iot_input.pot | 10 +++++----- iot_input_oca/models/iot_device.py | 3 ++- iot_input_oca/readme/USAGE.rst | 10 ++++++++-- iot_input_oca/static/description/index.html | 10 ++++++++-- iot_input_oca/tests/test_iot_in.py | 14 ++++++++++++++ 8 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 iot_input_oca/examples/multi_input_values.json diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index fe9af15d..26438480 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -77,7 +77,13 @@ 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 and array of values for input +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:: @@ -91,7 +97,7 @@ It requires the function that the system will call must be of the following kind 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 return along with the object for the IoT device to identify +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 diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 99d7376f..b9f7a433 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { 'name': 'IoT Input', - 'version': '12.0.1.1.0', + 'version': '12.0.1.2.0', 'category': 'IoT', 'author': "Creu Blanca, " "Odoo Community Association (OCA)", diff --git a/iot_input_oca/examples/multi_input_values.json b/iot_input_oca/examples/multi_input_values.json new file mode 100644 index 00000000..469f9bff --- /dev/null +++ b/iot_input_oca/examples/multi_input_values.json @@ -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 + } +] diff --git a/iot_input_oca/i18n/iot_input.pot b/iot_input_oca/i18n/iot_input.pot index 08f0b158..e4179615 100644 --- a/iot_input_oca/i18n/iot_input.pot +++ b/iot_input_oca/i18n/iot_input.pot @@ -101,7 +101,7 @@ msgid "Display Name" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device.py:126 +#: code:addons/iot_input/models/iot_device.py:127 #, python-format msgid "Empty values array" msgstr "" @@ -215,10 +215,10 @@ msgid "Server Error" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device.py:77 -#: code:addons/iot_input/models/iot_device.py:107 -#: code:addons/iot_input/models/iot_device.py:113 -#: code:addons/iot_input/models/iot_device.py:119 +#: code:addons/iot_input/models/iot_device.py:78 +#: code:addons/iot_input/models/iot_device.py:108 +#: code:addons/iot_input/models/iot_device.py:114 +#: code:addons/iot_input/models/iot_device.py:120 #, python-format msgid "Server Error. Check server logs" msgstr "" diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py index 3d6a7d06..0b5a6270 100644 --- a/iot_input_oca/models/iot_device.py +++ b/iot_input_oca/models/iot_device.py @@ -63,7 +63,8 @@ def parse_single_input(self, value): msg['uuid'] = value['uuid'] return msg - device_input = self.input_ids.filtered(lambda i: i.address == value['address']) + device_input = self.input_ids.filtered( + lambda i: i.address == str(value['address'])) if len(device_input) == 1: res = device_input._call_device(value) self.env['iot.device.input.action'].create( diff --git a/iot_input_oca/readme/USAGE.rst b/iot_input_oca/readme/USAGE.rst index 5412cef4..d7d24727 100644 --- a/iot_input_oca/readme/USAGE.rst +++ b/iot_input_oca/readme/USAGE.rst @@ -27,7 +27,13 @@ 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 and array of values for input +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:: @@ -41,7 +47,7 @@ It requires the function that the system will call must be of the following kind 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 return along with the object for the IoT device to identify +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 diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index bc4ae2f3..8d31247c 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -420,7 +420,13 @@

Usage

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 and array of values for input

+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
@@ -432,7 +438,7 @@ 

Usage

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 return along with the object for the IoT device to identify +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 diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index 0681bd95..2fd28901 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -134,6 +134,20 @@ def test_multi_input(self): [x for x in response_with_uuid if x['uuid'] == response['uuid']][0] ) + # Test for address passed as number + address_3 = 3 + self.env['iot.device.input'].create({ + 'name': 'Input 1', + 'device_id': device.id, + 'address': address_3, + 'call_model_id': self.ref('iot_input.model_iot_device_input'), + 'call_function': 'test_model_function' + }) + for response in device.parse_multi_input( + device_identification, passphrase, + [{'address': address_3, 'value': 12.3}]): + self.assertEqual(response['status'], 'ok') + device.active = False self.assertEqual(device.parse_multi_input( device_identification, passphrase, From 68abae3f5caedc0f5fa922eb8a4d7681d22a25f3 Mon Sep 17 00:00:00 2001 From: "Dimitrios T. Tanis" Date: Thu, 21 Jan 2021 12:22:15 +0200 Subject: [PATCH 04/31] [12.0][UPD]iot,iot_input: set order,skip inactive inputs -Sets default order to name for iot_device and iot_input -Skips parsing data for inactive inputs --- iot_input_oca/__manifest__.py | 2 +- iot_input_oca/i18n/iot_input.pot | 15 ++++++++------- iot_input_oca/models/iot_device.py | 9 +++++++++ iot_input_oca/models/iot_device_input.py | 1 + 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index b9f7a433..4fe63c77 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { 'name': 'IoT Input', - 'version': '12.0.1.2.0', + 'version': '12.0.1.3.0', 'category': 'IoT', 'author': "Creu Blanca, " "Odoo Community Association (OCA)", diff --git a/iot_input_oca/i18n/iot_input.pot b/iot_input_oca/i18n/iot_input.pot index e4179615..7635dc30 100644 --- a/iot_input_oca/i18n/iot_input.pot +++ b/iot_input_oca/i18n/iot_input.pot @@ -84,7 +84,7 @@ msgid "Device" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device_input.py:60 +#: code:addons/iot_input/models/iot_device_input.py:61 #, python-format msgid "Device cannot be found" msgstr "" @@ -101,7 +101,7 @@ msgid "Display Name" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device.py:127 +#: code:addons/iot_input/models/iot_device.py:136 #, python-format msgid "Empty values array" msgstr "" @@ -203,7 +203,7 @@ msgid "Serial" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device_input.py:46 +#: code:addons/iot_input/models/iot_device_input.py:47 #, python-format msgid "Serial and passphrase are required" msgstr "" @@ -215,10 +215,11 @@ msgid "Server Error" msgstr "" #. module: iot_input -#: code:addons/iot_input/models/iot_device.py:78 -#: code:addons/iot_input/models/iot_device.py:108 -#: code:addons/iot_input/models/iot_device.py:114 -#: code:addons/iot_input/models/iot_device.py:120 +#: 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 "" diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py index 0b5a6270..34b773aa 100644 --- a/iot_input_oca/models/iot_device.py +++ b/iot_input_oca/models/iot_device.py @@ -66,6 +66,15 @@ def parse_single_input(self, value): device_input = self.input_ids.filtered( lambda i: i.address == str(value['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 = {'status': 'error', + 'message': _('Server Error. Check server logs')} + if 'uuid' in value: + msg['uuid'] = value['uuid'] + return msg res = device_input._call_device(value) self.env['iot.device.input.action'].create( device_input._add_action_vals(value, res)) diff --git a/iot_input_oca/models/iot_device_input.py b/iot_input_oca/models/iot_device_input.py index 75749d36..54496e7f 100644 --- a/iot_input_oca/models/iot_device_input.py +++ b/iot_input_oca/models/iot_device_input.py @@ -5,6 +5,7 @@ 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) From e3660dcaf91fcaa2ca5f2f4a9124632bda7e55a9 Mon Sep 17 00:00:00 2001 From: Olga Marco Date: Wed, 9 Jun 2021 09:24:17 +0200 Subject: [PATCH 05/31] [IMP] iot_input_oca: black, isort, prettier --- iot_input_oca/__manifest__.py | 30 +- .../controller/iot_input_controller.py | 98 ++++--- .../examples/multi_input_values.json | 34 +-- iot_input_oca/models/iot_device.py | 129 ++++----- iot_input_oca/models/iot_device_input.py | 50 ++-- iot_input_oca/models/mail_message.py | 15 +- iot_input_oca/tests/test_iot_in.py | 269 ++++++++++-------- .../views/iot_device_input_views.xml | 64 +++-- iot_input_oca/views/iot_device_views.xml | 17 +- 9 files changed, 382 insertions(+), 324 deletions(-) diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 4fe63c77..24dd6280 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -1,22 +1,18 @@ # Copyright (C) 2018 Creu Blanca # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'IoT Input', - 'version': '12.0.1.3.0', - 'category': 'IoT', - 'author': "Creu Blanca, " - "Odoo Community Association (OCA)", - 'license': 'AGPL-3', - 'installable': True, - 'summary': 'IoT Input module', - 'depends': [ - 'iot_output', - 'mail', - ], - 'maintainers': ['etobella'], - 'data': [ - 'security/ir.model.access.csv', - 'views/iot_device_views.xml', - 'views/iot_device_input_views.xml', + "name": "IoT Input", + "version": "12.0.1.3.0", + "category": "IoT", + "author": "Creu Blanca, " "Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "summary": "IoT Input module", + "depends": ["iot_output", "mail",], + "maintainers": ["etobella"], + "data": [ + "security/ir.model.access.csv", + "views/iot_device_views.xml", + "views/iot_device_input_views.xml", ], } diff --git a/iot_input_oca/controller/iot_input_controller.py b/iot_input_oca/controller/iot_input_controller.py index bf23778f..f7c8c626 100644 --- a/iot_input_oca/controller/iot_input_controller.py +++ b/iot_input_oca/controller/iot_input_controller.py @@ -3,76 +3,96 @@ import json import logging -from odoo import http, _ + +from odoo import _, http _logger = logging.getLogger(__name__) class CallIot(http.Controller): - @http.route([ - '/iot//action', - ], type='http', auth="none", methods=['POST'], csrf=False) + @http.route( + ["/iot//action",], + type="http", + auth="none", + methods=["POST"], + csrf=False, + ) def call_unauthorized_iot(self, serial, *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, kwargs['passphrase']).call_device(kwargs['value'])) + return json.dumps( + request.env["iot.device.input"] + .sudo() + .get_device(serial, kwargs["passphrase"]) + .call_device(kwargs["value"]) + ) - @http.route([ - '/iot//multi_input', - ], type='http', auth="none", methods=['POST'], csrf=False) - def call_unauthorized_iot_multi_input( - self, device_identification, *args, **kwargs): - '''Controller to write multiple input data to device inputs + @http.route( + ["/iot//multi_input",], + type="http", + auth="none", + methods=["POST"], + csrf=False, + ) + def call_unauthorized_iot_multi_input(self, device_identification, *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 'passphrase' not in kwargs: - _logger.warning('Passphrase is required') - return json.dumps({'status': 'error', - 'message': _('Passphrase is required')}) - if 'values' not in kwargs: - _logger.warning('Values is required') - return json.dumps({'status': 'error', - 'message': _('Values is required')}) + _logger.warning("env not set") + return json.dumps({"status": "error", "message": _("Server Error")}) + if "passphrase" not in kwargs: + _logger.warning("Passphrase is required") + return json.dumps( + {"status": "error", "message": _("Passphrase is required")} + ) + if "values" not in kwargs: + _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: - values = json.loads(kwargs['values']) + values = json.loads(kwargs["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')}) + _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')}) + _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 return json.dumps( - request.env['iot.device'].sudo().parse_multi_input( - device_identification, kwargs['passphrase'], values)) + request.env["iot.device"] + .sudo() + .parse_multi_input(device_identification, kwargs["passphrase"], values) + ) - @http.route([ - '/iot//check', - ], type='http', auth="none", methods=['POST'], csrf=False) + @http.route( + ["/iot//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']) + device = ( + request.env["iot.device.input"] + .sudo() + .get_device(serial, kwargs["passphrase"]) + ) if device: return json.dumps({"state": True}) return json.dumps({"state": False}) diff --git a/iot_input_oca/examples/multi_input_values.json b/iot_input_oca/examples/multi_input_values.json index 469f9bff..36b503a3 100644 --- a/iot_input_oca/examples/multi_input_values.json +++ b/iot_input_oca/examples/multi_input_values.json @@ -1,19 +1,19 @@ [ - { - "address": "ZMPT101B_1", - "value": 230 - }, - { - "address": 1, - "value": true - }, - { - "address": 2, - "value": "Door opened", - "uuid": "abcde" - }, - { - "address": 10, - "value": -18.5 - } + { + "address": "ZMPT101B_1", + "value": 230 + }, + { + "address": 1, + "value": true + }, + { + "address": 2, + "value": "Door opened", + "uuid": "abcde" + }, + { + "address": 10, + "value": -18.5 + } ] diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py index 34b773aa..10dd1e21 100644 --- a/iot_input_oca/models/iot_device.py +++ b/iot_input_oca/models/iot_device.py @@ -1,20 +1,17 @@ import logging -from odoo import api, fields, models, _ +from odoo import _, api, fields, models _logger = logging.getLogger(__name__) class IotDevice(models.Model): - _inherit = 'iot.device' + _inherit = "iot.device" - input_ids = fields.One2many( - 'iot.device.input', - inverse_name='device_id' - ) - input_count = fields.Integer(compute='_compute_input_count') + input_ids = fields.One2many("iot.device.input", inverse_name="device_id") + input_count = fields.Integer(compute="_compute_input_count") - @api.depends('input_ids') + @api.depends("input_ids") def _compute_input_count(self): for r in self: r.input_count = len(r.input_ids) @@ -22,22 +19,21 @@ def _compute_input_count(self): @api.multi def action_show_input(self): self.ensure_one() - action = self.env.ref('iot_input.iot_device_input_action') + action = self.env.ref("iot_input.iot_device_input_action") result = action.read()[0] - result['context'] = { - 'default_device_id': self.id, + result["context"] = { + "default_device_id": self.id, } - result['domain'] = "[('device_id', '=', " + \ - str(self.id) + ")]" + result["domain"] = "[('device_id', '=', " + str(self.id) + ")]" if len(self.input_ids) == 1: - result['views'] = [(False, 'form')] - result['res_id'] = self.input_ids.id + result["views"] = [(False, "form")] + result["res_id"] = self.input_ids.id return result @api.multi def parse_single_input(self, value): - '''Handle single input for device + """Handle single input for device :param dict value: Dict containing at least keys 'address', 'value' @@ -47,51 +43,53 @@ def parse_single_input(self, value): 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 - ''' - if 'address' not in value.keys(): - _logger.warning('Address for Input is required') - msg = {'status': 'error', - 'message': _('Address for Input is required')} - if 'uuid' in value.keys(): - msg['uuid'] = value['uuid'] + """ + if "address" not in value.keys(): + _logger.warning("Address for Input is required") + msg = {"status": "error", "message": _("Address for Input is required")} + if "uuid" in value.keys(): + msg["uuid"] = value["uuid"] return msg - if 'value' not in value.keys(): - _logger.warning('Value for Input is required') - msg = {'status': 'error', - 'message': _('Value for Input is required')} - if 'uuid' in value.keys(): - msg['uuid'] = value['uuid'] + if "value" not in value.keys(): + _logger.warning("Value for Input is required") + msg = {"status": "error", "message": _("Value for Input is required")} + if "uuid" in value.keys(): + msg["uuid"] = value["uuid"] return msg device_input = self.input_ids.filtered( - lambda i: i.address == str(value['address'])) + lambda i: i.address == str(value["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 = {'status': 'error', - 'message': _('Server Error. Check server logs')} - if 'uuid' in value: - msg['uuid'] = value['uuid'] + "Input with address %s is inactive, no data will be logged", + device_input.address, + ) + msg = { + "status": "error", + "message": _("Server Error. Check server logs"), + } + if "uuid" in value: + msg["uuid"] = value["uuid"] return msg res = device_input._call_device(value) - self.env['iot.device.input.action'].create( - device_input._add_action_vals(value, res)) - if 'uuid' in value: - res['uuid'] = value['uuid'] + self.env["iot.device.input.action"].create( + device_input._add_action_vals(value, res) + ) + if "uuid" in value: + res["uuid"] = value["uuid"] return res else: - _logger.warning('Input with address %s not found', value['address']) - msg = {'status': 'error', - 'message': _('Server Error. Check server logs')} - if 'uuid' in value: - msg['uuid'] = value['uuid'] + _logger.warning("Input with address %s not found", value["address"]) + msg = {"status": "error", "message": _("Server Error. Check server logs")} + if "uuid" in value: + msg["uuid"] = value["uuid"] return msg @api.model def parse_multi_input(self, device_identification, passphrase, values): - '''Handle multiple inputs for device + """Handle multiple inputs for device :param string device_identification: Device identification. @@ -105,35 +103,34 @@ def parse_multi_input(self, device_identification, passphrase, values): - Mix of the above (multi input, multi event) :returns: JSON encodable list of dicts :rtype: list - ''' - device = self.with_context( - active_test=False).search( - [('device_identification', '=', device_identification)]) + """ + device = self.with_context(active_test=False).search( + [("device_identification", "=", device_identification)] + ) if not device: _logger.warning( - 'Device with identification %s not found', - device_identification) - return {'status': 'error', - 'message': _('Server Error. Check server logs')} + "Device with identification %s not found", device_identification + ) + return {"status": "error", "message": _("Server Error. Check server logs")} if not device.active: _logger.warning( - 'Device with identification %s is inactive, no data will be logged', - device.device_identification) - return {'status': 'error', - 'message': _('Server Error. Check server logs')} + "Device with identification %s is inactive, no data will be logged", + device.device_identification, + ) + return {"status": "error", "message": _("Server Error. Check server logs")} if device.passphrase != passphrase: _logger.warning( - 'Wrong passphrase for device with identification %s', - device.device_identification) - return {'status': 'error', - 'message': _('Server Error. Check server logs')} + "Wrong passphrase for device with identification %s", + device.device_identification, + ) + return {"status": "error", "message": _("Server Error. Check server logs")} if not values: _logger.warning( - 'Empty values array for device with identification %s', - device.device_identification) - return {'status': 'error', - 'message': _('Empty values array')} + "Empty values array for device with identification %s", + device.device_identification, + ) + return {"status": "error", "message": _("Empty values array")} res = [] for d in values: res.append(device.parse_single_input(d)) diff --git a/iot_input_oca/models/iot_device_input.py b/iot_input_oca/models/iot_device_input.py index 54496e7f..218d5cc8 100644 --- a/iot_input_oca/models/iot_device_input.py +++ b/iot_input_oca/models/iot_device_input.py @@ -1,30 +1,29 @@ -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class IotDeviceInput(models.Model): - _name = 'iot.device.input' + _name = "iot.device.input" _description = "Device input" - _order = 'name' + _order = "name" name = fields.Char(required=True) - device_id = fields.Many2one('iot.device', required=True, readonly=True) - call_model_id = fields.Many2one('ir.model') + device_id = fields.Many2one("iot.device", required=True, readonly=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, + "iot.device.input.action", inverse_name="input_id", readonly=True, ) - action_count = fields.Integer(compute='_compute_action_count') + action_count = fields.Integer(compute="_compute_action_count") lang = fields.Selection( - selection=lambda self: self.env['res.lang'].get_installed(), - string='Language', + selection=lambda self: self.env["res.lang"].get_installed(), string="Language", ) - @api.depends('action_ids') + @api.depends("action_ids") def _compute_action_count(self): for r in self: r.action_count = len(r.action_ids) @@ -44,8 +43,8 @@ def _call_device(self, value): def parse_args(self, serial, passphrase): if not serial or not passphrase: - raise ValidationError(_('Serial and passphrase are required')) - return [('serial', '=', serial), ('passphrase', '=', passphrase)] + raise ValidationError(_("Serial and passphrase are required")) + return [("serial", "=", serial), ("passphrase", "=", passphrase)] @api.model def get_device(self, serial, passphrase): @@ -53,39 +52,36 @@ def get_device(self, serial, passphrase): @api.model def get_auth_device(self, serial): - return self.search([('serial', '=', serial)], limit=1) + return self.search([("serial", "=", serial)], limit=1) @api.multi def call_device(self, value): if not self: - return {'status': 'error', 'message': _('Device cannot be found')} + return {"status": "error", "message": _("Device cannot be found")} else: res = self._call_device(value) - res['status'] = 'ok' - self.env['iot.device.input.action'].create( - self._add_action_vals(value, res)) + res["status"] = "ok" + self.env["iot.device.input.action"].create(self._add_action_vals(value, res)) return res def _add_action_vals(self, value, res): return { - 'input_id': self.id, - 'args': str(value), - 'res': str(res), + "input_id": self.id, + "args": str(value), + "res": str(res), } def test_input_device(self, value): - return {'value': value} + return {"value": value} def test_model_function(self, value): - return {'status': 'ok', - 'message': value - } + return {"status": "ok", "message": value} class IoTDeviceAction(models.Model): - _name = 'iot.device.input.action' - _description = 'Action of device inputs' + _name = "iot.device.input.action" + _description = "Action of device inputs" - input_id = fields.Many2one('iot.device.input') + input_id = fields.Many2one("iot.device.input") args = fields.Char() res = fields.Char() diff --git a/iot_input_oca/models/mail_message.py b/iot_input_oca/models/mail_message.py index e0d47b4b..bba4a9d4 100644 --- a/iot_input_oca/models/mail_message.py +++ b/iot_input_oca/models/mail_message.py @@ -1,16 +1,17 @@ -from odoo import api, models, _ +from odoo import _, api, models class MailMessage(models.Model): - _inherit = 'mail.message' + _inherit = "mail.message" @api.model def create(self, vals): - device = self.env.context.get('iot_device_name', False) + device = self.env.context.get("iot_device_name", False) if device: - body = vals.get('body', '') + body = vals.get("body", "") if len(body) > 0: - body += '
' - vals['body'] = '%s%s' % ( - body, _('Detected automatically by %s') % device) + body += "
" + vals["body"] = "{}{}".format( + body, _("Detected automatically by %s") % device + ) return super().create(vals) diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index 2fd28901..1113a455 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -3,152 +3,189 @@ class TestIotIn(TransactionCase): def test_device(self): - serial = 'testingdeviceserial' - passphrase = 'password' - device = self.env['iot.device'].create({ - 'name': 'Device', - }) - device_input = self.env['iot.device.input'].create({ - 'name': 'Input', - 'device_id': device.id, - 'active': True, - 'serial': serial, - 'passphrase': passphrase, - 'call_model_id': self.ref('iot_input.model_iot_device_input'), - 'call_function': 'test_input_device' - }) - iot = self.env['iot.device.input'] + serial = "testingdeviceserial" + passphrase = "password" + device = self.env["iot.device"].create({"name": "Device",}) + device_input = self.env["iot.device.input"].create( + { + "name": "Input", + "device_id": device.id, + "active": True, + "serial": serial, + "passphrase": passphrase, + "call_model_id": self.ref("iot_input.model_iot_device_input"), + "call_function": "test_input_device", + } + ) + iot = self.env["iot.device.input"] + self.assertFalse(iot.get_device(serial=serial + serial, passphrase=passphrase)) self.assertFalse( - iot.get_device(serial=serial + serial, passphrase=passphrase)) - self.assertFalse( - iot.get_device(serial=serial, passphrase=passphrase + passphrase)) - iot = iot.get_device( - serial=serial, passphrase=passphrase) + iot.get_device(serial=serial, passphrase=passphrase + passphrase) + ) + iot = iot.get_device(serial=serial, passphrase=passphrase) self.assertEqual(iot, device_input) - args = 'hello' + args = "hello" res = iot.call_device(args) - self.assertEqual(res, {'status': 'ok', 'value': args}) + self.assertEqual(res, {"status": "ok", "value": args}) self.assertTrue(device_input.action_ids) self.assertEqual(device_input.action_ids.args, str(args)) self.assertEqual(device_input.action_ids.res, str(res)) def test_multi_input(self): - device_identification = 'test_device_name' - passphrase = 'password' - device = self.env['iot.device'].create({ - 'name': 'Device', - 'device_identification': device_identification, - 'passphrase': passphrase - }) - address_1 = 'I0' - self.env['iot.device.input'].create({ - 'name': 'Input 1', - 'device_id': device.id, - 'address': address_1, - 'call_model_id': self.ref('iot_input.model_iot_device_input'), - 'call_function': 'test_model_function' - }) - address_2 = 'I1' - self.env['iot.device.input'].create({ - 'name': 'Input 2', - 'device_id': device.id, - 'address': address_2, - 'call_model_id': self.ref('iot_input.model_iot_device_input'), - 'call_function': 'test_model_function' - }) - single_input_values = [{'input': address_1, 'value': 'test'}] - self.assertEqual(device.parse_multi_input( - device_identification + device_identification, passphrase, - single_input_values)['status'], 'error') - self.assertEqual(device.parse_multi_input( - device_identification, passphrase + passphrase, - single_input_values)['status'], 'error') - self.assertEqual(device.parse_multi_input( - device_identification, passphrase, False)['status'], 'error') + device_identification = "test_device_name" + passphrase = "password" + device = self.env["iot.device"].create( + { + "name": "Device", + "device_identification": device_identification, + "passphrase": passphrase, + } + ) + address_1 = "I0" + self.env["iot.device.input"].create( + { + "name": "Input 1", + "device_id": device.id, + "address": address_1, + "call_model_id": self.ref("iot_input.model_iot_device_input"), + "call_function": "test_model_function", + } + ) + address_2 = "I1" + self.env["iot.device.input"].create( + { + "name": "Input 2", + "device_id": device.id, + "address": address_2, + "call_model_id": self.ref("iot_input.model_iot_device_input"), + "call_function": "test_model_function", + } + ) + single_input_values = [{"input": address_1, "value": "test"}] + self.assertEqual( + device.parse_multi_input( + device_identification + device_identification, + passphrase, + single_input_values, + )["status"], + "error", + ) + self.assertEqual( + device.parse_multi_input( + device_identification, passphrase + passphrase, single_input_values + )["status"], + "error", + ) + self.assertEqual( + device.parse_multi_input(device_identification, passphrase, False)[ + "status" + ], + "error", + ) for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1}]): - self.assertEqual(response['status'], 'error') + device_identification, passphrase, [{"address": address_1}] + ): + self.assertEqual(response["status"], "error") for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'uuid': 'abc'}]): - self.assertEqual(response['status'], 'error') - self.assertTrue('uuid' in response) + device_identification, passphrase, [{"address": address_1, "uuid": "abc"}] + ): + self.assertEqual(response["status"], "error") + self.assertTrue("uuid" in response) for response in device.parse_multi_input( - device_identification, passphrase, - [{'value': 'test value'}]): - self.assertEqual(response['status'], 'error') + device_identification, passphrase, [{"value": "test value"}] + ): + self.assertEqual(response["status"], "error") for response in device.parse_multi_input( - device_identification, passphrase, - [{'value': 'test value', 'uuid': 'abc'}]): - self.assertEqual(response['status'], 'error') - self.assertTrue('uuid' in response) + device_identification, passphrase, [{"value": "test value", "uuid": "abc"}] + ): + self.assertEqual(response["status"], "error") + self.assertTrue("uuid" in response) - non_existing_address = 'I3' + non_existing_address = "I3" for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': non_existing_address, - 'value': 'test value 1'}]): - self.assertEqual(response['status'], 'error') + device_identification, + passphrase, + [{"address": non_existing_address, "value": "test value 1"}], + ): + self.assertEqual(response["status"], "error") for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': non_existing_address, - 'value': 'test value 1', - 'uuid': 'abc'}]): - self.assertEqual(response['status'], 'error') - self.assertTrue('uuid' in response) + device_identification, + passphrase, + [{"address": non_existing_address, "value": "test value 1", "uuid": "abc"}], + ): + self.assertEqual(response["status"], "error") + self.assertTrue("uuid" in response) for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'value': 'test'}]): - self.assertEqual(response['status'], 'ok') + device_identification, passphrase, [{"address": address_1, "value": "test"}] + ): + self.assertEqual(response["status"], "ok") for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'value': 'test value 1'}, - {'address': address_1, 'value': 'test value 2'}]): - self.assertEqual(response['status'], 'ok') + device_identification, + passphrase, + [ + {"address": address_1, "value": "test value 1"}, + {"address": address_1, "value": "test value 2"}, + ], + ): + self.assertEqual(response["status"], "ok") for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'value': 'test value 1'}, - {'address': address_2, 'value': 'test value 2'}]): - self.assertEqual(response['status'], 'ok') + device_identification, + passphrase, + [ + {"address": address_1, "value": "test value 1"}, + {"address": address_2, "value": "test value 2"}, + ], + ): + self.assertEqual(response["status"], "ok") for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'value': 'test value 1'}, - {'address': address_1, 'value': 'test value 2'}, - {'address': address_2, 'value': 'test value 3'}]): - self.assertEqual(response['status'], 'ok') + device_identification, + passphrase, + [ + {"address": address_1, "value": "test value 1"}, + {"address": address_1, "value": "test value 2"}, + {"address": address_2, "value": "test value 3"}, + ], + ): + self.assertEqual(response["status"], "ok") response_with_uuid = [ - {'address': address_1, 'value': 'test value 1', 'uuid': 'abc'}, - {'address': address_1, 'value': 'test value 2', 'uuid': 'def'}, - {'address': address_2, 'value': 'test value 3', 'uuid': 'ghi'} + {"address": address_1, "value": "test value 1", "uuid": "abc"}, + {"address": address_1, "value": "test value 2", "uuid": "def"}, + {"address": address_2, "value": "test value 3", "uuid": "ghi"}, ] for response in device.parse_multi_input( - device_identification, passphrase, - response_with_uuid): - self.assertTrue(response['uuid']) + device_identification, passphrase, response_with_uuid + ): + self.assertTrue(response["uuid"]) self.assertEqual( - response['message'], - [x for x in response_with_uuid if x['uuid'] == response['uuid']][0] + response["message"], + [x for x in response_with_uuid if x["uuid"] == response["uuid"]][0], ) # Test for address passed as number address_3 = 3 - self.env['iot.device.input'].create({ - 'name': 'Input 1', - 'device_id': device.id, - 'address': address_3, - 'call_model_id': self.ref('iot_input.model_iot_device_input'), - 'call_function': 'test_model_function' - }) + self.env["iot.device.input"].create( + { + "name": "Input 1", + "device_id": device.id, + "address": address_3, + "call_model_id": self.ref("iot_input.model_iot_device_input"), + "call_function": "test_model_function", + } + ) for response in device.parse_multi_input( - device_identification, passphrase, - [{'address': address_3, 'value': 12.3}]): - self.assertEqual(response['status'], 'ok') + device_identification, passphrase, [{"address": address_3, "value": 12.3}] + ): + self.assertEqual(response["status"], "ok") device.active = False - self.assertEqual(device.parse_multi_input( - device_identification, passphrase, - [{'address': address_1, 'value': 'test'}])['status'], 'error') + self.assertEqual( + device.parse_multi_input( + device_identification, + passphrase, + [{"address": address_1, "value": "test"}], + )["status"], + "error", + ) diff --git a/iot_input_oca/views/iot_device_input_views.xml b/iot_input_oca/views/iot_device_input_views.xml index 342521e1..9cfc0a3b 100644 --- a/iot_input_oca/views/iot_device_input_views.xml +++ b/iot_input_oca/views/iot_device_input_views.xml @@ -1,67 +1,80 @@ - iot.device.input.tree iot.device.input - - - + + + - iot.device.input.form iot.device.input -

+
-

- +

- - - + + + - - - + + + - +
- iot.device.input.search iot.device.input - - - - - + + + + + - IoT Inputs ir.actions.act_window @@ -69,5 +82,4 @@ form tree,form - diff --git a/iot_input_oca/views/iot_device_views.xml b/iot_input_oca/views/iot_device_views.xml index 0985c6ce..7ec80744 100644 --- a/iot_input_oca/views/iot_device_views.xml +++ b/iot_input_oca/views/iot_device_views.xml @@ -1,21 +1,20 @@ - iot.device.form iot.device - + - - From d6017a50df4cce09b1ce00c766f18f79c640ee86 Mon Sep 17 00:00:00 2001 From: Olga Marco Date: Wed, 9 Jun 2021 10:03:39 +0200 Subject: [PATCH 06/31] [MIG] iot_input_oca: Migration to 13.0 --- iot_input_oca/README.rst | 10 +- iot_input_oca/__manifest__.py | 7 +- .../controller/iot_input_controller.py | 6 +- iot_input_oca/i18n/iot_input_oca.pot | 249 +++++++++++++++++ iot_input_oca/models/iot_device.py | 37 ++- iot_input_oca/models/iot_device_input.py | 5 - iot_input_oca/security/ir.model.access.csv | 8 +- iot_input_oca/static/description/index.html | 6 +- iot_input_oca/tests/__init__.py | 3 + iot_input_oca/tests/models.py | 10 + iot_input_oca/tests/test_iot_controller.py | 113 ++++++++ iot_input_oca/tests/test_iot_in.py | 250 ++++++------------ iot_input_oca/tests/test_iot_message.py | 46 ++++ iot_input_oca/tests/test_iot_multi_input.py | 174 ++++++++++++ .../views/iot_device_input_views.xml | 23 +- iot_input_oca/views/iot_device_views.xml | 2 +- 16 files changed, 718 insertions(+), 231 deletions(-) create mode 100644 iot_input_oca/i18n/iot_input_oca.pot create mode 100644 iot_input_oca/tests/models.py create mode 100644 iot_input_oca/tests/test_iot_controller.py create mode 100644 iot_input_oca/tests/test_iot_message.py create mode 100644 iot_input_oca/tests/test_iot_multi_input.py diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index 26438480..73b71970 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -14,13 +14,13 @@ IoT Input :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/12.0/iot_input + :target: https://github.com/OCA/iot/tree/13.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-12-0/iot-12-0-iot_input + :target: https://translation.odoo-community.org/projects/iot-13-0/iot-13-0-iot_input_oca :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/269/12.0 + :target: https://runbot.odoo-community.org/runbot/269/13.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -110,7 +110,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -149,6 +149,6 @@ Current `maintainer `__: |maintainer-etobella| -This module is part of the `OCA/iot `_ project on GitHub. +This module is part of the `OCA/iot `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 24dd6280..31837fb6 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,13 +2,14 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "IoT Input", - "version": "12.0.1.3.0", + "version": "13.0.1.0.0", "category": "IoT", - "author": "Creu Blanca, " "Odoo Community Association (OCA)", + "author": "Creu Blanca, Odoo Community Association (OCA)", "license": "AGPL-3", "installable": True, "summary": "IoT Input module", - "depends": ["iot_output", "mail",], + "depends": ["iot_output_oca", "mail"], + "website": "https://github.com/OCA/iot", "maintainers": ["etobella"], "data": [ "security/ir.model.access.csv", diff --git a/iot_input_oca/controller/iot_input_controller.py b/iot_input_oca/controller/iot_input_controller.py index f7c8c626..a6b01412 100644 --- a/iot_input_oca/controller/iot_input_controller.py +++ b/iot_input_oca/controller/iot_input_controller.py @@ -11,7 +11,7 @@ class CallIot(http.Controller): @http.route( - ["/iot//action",], + ["/iot//action"], type="http", auth="none", methods=["POST"], @@ -29,7 +29,7 @@ def call_unauthorized_iot(self, serial, *args, **kwargs): ) @http.route( - ["/iot//multi_input",], + ["/iot//multi_input"], type="http", auth="none", methods=["POST"], @@ -82,7 +82,7 @@ def call_unauthorized_iot_multi_input(self, device_identification, *args, **kwar ) @http.route( - ["/iot//check",], type="http", auth="none", methods=["POST"], csrf=False + ["/iot//check"], type="http", auth="none", methods=["POST"], csrf=False ) def check_unauthorized_iot(self, serial, *args, **kwargs): request = http.request diff --git a/iot_input_oca/i18n/iot_input_oca.pot b/iot_input_oca/i18n/iot_input_oca.pot new file mode 100644 index 00000000..fd1a1a32 --- /dev/null +++ b/iot_input_oca/i18n/iot_input_oca.pot @@ -0,0 +1,249 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * iot_input_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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: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 +#: 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 +#: code:addons/iot_input_oca/models/mail_message.py:0 +#, python-format +msgid "Detected automatically by %s" +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 +#: 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 +#: code:addons/iot_input_oca/models/iot_device.py:0 +#, python-format +msgid "Empty values array" +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__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,name:iot_input_oca.model_mail_message +msgid "Message" +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 +#: 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 +#: code:addons/iot_input_oca/models/iot_device_input.py:0 +#, python-format +msgid "Serial and passphrase are required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Server Error" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/models/iot_device.py:0 +#: code:addons/iot_input_oca/models/iot_device.py:0 +#: code:addons/iot_input_oca/models/iot_device.py:0 +#: 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 +#: code:addons/iot_input_oca/models/iot_device.py:0 +#, python-format +msgid "Value for Input is required" +msgstr "" + +#. module: iot_input_oca +#: 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 +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values is required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values should be a JSON array of JSON objects" +msgstr "" diff --git a/iot_input_oca/models/iot_device.py b/iot_input_oca/models/iot_device.py index 10dd1e21..13fe028e 100644 --- a/iot_input_oca/models/iot_device.py +++ b/iot_input_oca/models/iot_device.py @@ -16,22 +16,20 @@ def _compute_input_count(self): for r in self: r.input_count = len(r.input_ids) - @api.multi def action_show_input(self): self.ensure_one() - action = self.env.ref("iot_input.iot_device_input_action") + 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', '=', " + str(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 - @api.multi def parse_single_input(self, value): """Handle single input for device @@ -44,17 +42,18 @@ def parse_single_input(self, value): to identify result for each entry at the iot end :rtype: dict """ + msg = {} + if "uuid" in value: + msg["uuid"] = value["uuid"] if "address" not in value.keys(): _logger.warning("Address for Input is required") - msg = {"status": "error", "message": _("Address for Input is required")} - if "uuid" in value.keys(): - msg["uuid"] = value["uuid"] + msg.update( + {"status": "error", "message": _("Address for Input is required")} + ) return msg if "value" not in value.keys(): _logger.warning("Value for Input is required") - msg = {"status": "error", "message": _("Value for Input is required")} - if "uuid" in value.keys(): - msg["uuid"] = value["uuid"] + msg.update({"status": "error", "message": _("Value for Input is required")}) return msg device_input = self.input_ids.filtered( @@ -66,12 +65,12 @@ def parse_single_input(self, value): "Input with address %s is inactive, no data will be logged", device_input.address, ) - msg = { - "status": "error", - "message": _("Server Error. Check server logs"), - } - if "uuid" in value: - msg["uuid"] = value["uuid"] + msg.update( + { + "status": "error", + "message": _("Server Error. Check server logs"), + } + ) return msg res = device_input._call_device(value) self.env["iot.device.input.action"].create( @@ -82,9 +81,9 @@ def parse_single_input(self, value): return res else: _logger.warning("Input with address %s not found", value["address"]) - msg = {"status": "error", "message": _("Server Error. Check server logs")} - if "uuid" in value: - msg["uuid"] = value["uuid"] + msg.update( + {"status": "error", "message": _("Server Error. Check server logs")} + ) return msg @api.model diff --git a/iot_input_oca/models/iot_device_input.py b/iot_input_oca/models/iot_device_input.py index 218d5cc8..33d6d0c8 100644 --- a/iot_input_oca/models/iot_device_input.py +++ b/iot_input_oca/models/iot_device_input.py @@ -50,11 +50,6 @@ def parse_args(self, serial, passphrase): def get_device(self, serial, passphrase): return self.search(self.parse_args(serial, passphrase), limit=1) - @api.model - def get_auth_device(self, serial): - return self.search([("serial", "=", serial)], limit=1) - - @api.multi def call_device(self, value): if not self: return {"status": "error", "message": _("Device cannot be found")} diff --git a/iot_input_oca/security/ir.model.access.csv b/iot_input_oca/security/ir.model.access.csv index ee3e9c5d..fe82dfc8 100644 --- a/iot_input_oca/security/ir.model.access.csv +++ b/iot_input_oca/security/ir.model.access.csv @@ -1,5 +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.group_iot_user,1,1,1,0 -manage_iot_device_input,access_iot_device_input,model_iot_device_input,iot.group_iot_manager,1,1,1,1 -access_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot.group_iot_user,1,1,1,0 -manage_iot_device_input_action,access_iot_device_input_action,model_iot_device_input_action,iot.group_iot_manager,1,1,1,1 +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 diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index 8d31247c..7120a77e 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -367,7 +367,7 @@

IoT Input

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

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.

@@ -449,7 +449,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -476,7 +476,7 @@

Maintainers

promote its widespread use.

Current maintainer:

etobella

-

This module is part of the OCA/iot project on GitHub.

+

This module is part of the OCA/iot project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/iot_input_oca/tests/__init__.py b/iot_input_oca/tests/__init__.py index 5ec21d93..0740ace6 100644 --- a/iot_input_oca/tests/__init__.py +++ b/iot_input_oca/tests/__init__.py @@ -1 +1,4 @@ from . import test_iot_in +from . import test_iot_multi_input +from . import test_iot_controller +from . import test_iot_message diff --git a/iot_input_oca/tests/models.py b/iot_input_oca/tests/models.py new file mode 100644 index 00000000..e2a2c4c9 --- /dev/null +++ b/iot_input_oca/tests/models.py @@ -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 {} diff --git a/iot_input_oca/tests/test_iot_controller.py b/iot_input_oca/tests/test_iot_controller.py new file mode 100644 index 00000000..221a962b --- /dev/null +++ b/iot_input_oca/tests/test_iot_controller.py @@ -0,0 +1,113 @@ +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.device = self.env["iot.device"].create( + { + "name": "Device", + "device_identification": self.device_identification, + "passphrase": self.passphrase, + } + ) + 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.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_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}, + ) + for response in res.json(): + 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) diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index 1113a455..4444e6f2 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -1,191 +1,95 @@ -from odoo.tests.common import TransactionCase +from odoo.exceptions import ValidationError +from odoo.tests.common import SavepointCase -class TestIotIn(TransactionCase): - def test_device(self): - serial = "testingdeviceserial" - passphrase = "password" - device = self.env["iot.device"].create({"name": "Device",}) - device_input = self.env["iot.device.input"].create( +class TestIotIn(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.serial = "testingdeviceserial" + cls.passphrase = "password" + cls.device = cls.env["iot.device"].create({"name": "Device"}) + cls.device_input = cls.env["iot.device.input"].create( { "name": "Input", - "device_id": device.id, + "device_id": cls.device.id, "active": True, - "serial": serial, - "passphrase": passphrase, - "call_model_id": self.ref("iot_input.model_iot_device_input"), + "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", } ) - iot = self.env["iot.device.input"] - self.assertFalse(iot.get_device(serial=serial + serial, passphrase=passphrase)) - self.assertFalse( - iot.get_device(serial=serial, passphrase=passphrase + passphrase) - ) - iot = iot.get_device(serial=serial, passphrase=passphrase) - self.assertEqual(iot, device_input) - args = "hello" - res = iot.call_device(args) - self.assertEqual(res, {"status": "ok", "value": args}) - self.assertTrue(device_input.action_ids) - self.assertEqual(device_input.action_ids.args, str(args)) - self.assertEqual(device_input.action_ids.res, str(res)) + cls.iot = cls.env["iot.device.input"] - def test_multi_input(self): - device_identification = "test_device_name" - passphrase = "password" - device = self.env["iot.device"].create( - { - "name": "Device", - "device_identification": device_identification, - "passphrase": passphrase, - } - ) - address_1 = "I0" - self.env["iot.device.input"].create( - { - "name": "Input 1", - "device_id": device.id, - "address": address_1, - "call_model_id": self.ref("iot_input.model_iot_device_input"), - "call_function": "test_model_function", - } - ) - address_2 = "I1" - self.env["iot.device.input"].create( + 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 2", - "device_id": device.id, - "address": address_2, - "call_model_id": self.ref("iot_input.model_iot_device_input"), - "call_function": "test_model_function", + "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", } ) - single_input_values = [{"input": address_1, "value": "test"}] - self.assertEqual( - device.parse_multi_input( - device_identification + device_identification, - passphrase, - single_input_values, - )["status"], - "error", - ) - self.assertEqual( - device.parse_multi_input( - device_identification, passphrase + passphrase, single_input_values - )["status"], - "error", - ) - self.assertEqual( - device.parse_multi_input(device_identification, passphrase, False)[ - "status" - ], - "error", - ) - - for response in device.parse_multi_input( - device_identification, passphrase, [{"address": address_1}] - ): - self.assertEqual(response["status"], "error") - for response in device.parse_multi_input( - device_identification, passphrase, [{"address": address_1, "uuid": "abc"}] - ): - self.assertEqual(response["status"], "error") - self.assertTrue("uuid" in response) - - for response in device.parse_multi_input( - device_identification, passphrase, [{"value": "test value"}] - ): - self.assertEqual(response["status"], "error") - for response in device.parse_multi_input( - device_identification, passphrase, [{"value": "test value", "uuid": "abc"}] - ): - self.assertEqual(response["status"], "error") - self.assertTrue("uuid" in response) + devices = self._get_devices() + self.assertIn(self.device_input, devices) + self.assertIn(device_input_02, devices) - non_existing_address = "I3" - for response in device.parse_multi_input( - device_identification, - passphrase, - [{"address": non_existing_address, "value": "test value 1"}], - ): - self.assertEqual(response["status"], "error") - for response in device.parse_multi_input( - device_identification, - passphrase, - [{"address": non_existing_address, "value": "test value 1", "uuid": "abc"}], - ): - self.assertEqual(response["status"], "error") - self.assertTrue("uuid" in response) - - for response in device.parse_multi_input( - device_identification, passphrase, [{"address": address_1, "value": "test"}] - ): - self.assertEqual(response["status"], "ok") - for response in device.parse_multi_input( - device_identification, - passphrase, - [ - {"address": address_1, "value": "test value 1"}, - {"address": address_1, "value": "test value 2"}, - ], - ): - self.assertEqual(response["status"], "ok") - for response in device.parse_multi_input( - device_identification, - passphrase, - [ - {"address": address_1, "value": "test value 1"}, - {"address": address_2, "value": "test value 2"}, - ], - ): - self.assertEqual(response["status"], "ok") - for response in device.parse_multi_input( - device_identification, - passphrase, - [ - {"address": address_1, "value": "test value 1"}, - {"address": address_1, "value": "test value 2"}, - {"address": address_2, "value": "test value 3"}, - ], - ): - self.assertEqual(response["status"], "ok") - response_with_uuid = [ - {"address": address_1, "value": "test value 1", "uuid": "abc"}, - {"address": address_1, "value": "test value 2", "uuid": "def"}, - {"address": address_2, "value": "test value 3", "uuid": "ghi"}, - ] - for response in device.parse_multi_input( - device_identification, passphrase, response_with_uuid - ): - self.assertTrue(response["uuid"]) - self.assertEqual( - response["message"], - [x for x in response_with_uuid if x["uuid"] == response["uuid"]][0], + def test_device_error_wrong_serial(self): + self.assertFalse( + self.iot.get_device( + serial=self.serial + self.serial, passphrase=self.passphrase ) + ) - # Test for address passed as number - address_3 = 3 - self.env["iot.device.input"].create( - { - "name": "Input 1", - "device_id": device.id, - "address": address_3, - "call_model_id": self.ref("iot_input.model_iot_device_input"), - "call_function": "test_model_function", - } + def test_device_error_wrong_passphrase(self): + self.assertFalse( + self.iot.get_device( + serial=self.serial, passphrase=self.passphrase + self.passphrase + ) ) - for response in device.parse_multi_input( - device_identification, passphrase, [{"address": address_3, "value": 12.3}] - ): - self.assertEqual(response["status"], "ok") - device.active = False - self.assertEqual( - device.parse_multi_input( - device_identification, - passphrase, - [{"address": address_1, "value": "test"}], - )["status"], - "error", + 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("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(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) diff --git a/iot_input_oca/tests/test_iot_message.py b/iot_input_oca/tests/test_iot_message.py new file mode 100644 index 00000000..2df859b6 --- /dev/null +++ b/iot_input_oca/tests/test_iot_message.py @@ -0,0 +1,46 @@ +from odoo_test_helper import FakeModelLoader + +from odoo.tests import SavepointCase + + +class TestIotInputMessage(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + + from .models import ResPartner + + cls.loader.update_registry((ResPartner,)) + + cls.partner = cls.env["res.partner"].create({"name": "IoT demo partner"}) + cls.serial = "testingdeviceserial" + cls.passphrase = "password" + cls.device = cls.env["iot.device"].create({"name": "Device"}) + 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("base.model_res_partner").id, + "call_function": "test_fake_iot_input", + } + ) + cls.iot = cls.env["iot.device.input"] + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super().tearDownClass() + + def test_message(self): + original_messages = self.partner.message_ids + res = self.device_input.call_device(self.partner.id) + self.assertEqual("ok", res["status"]) + new_message = self.partner.message_ids - original_messages + self.assertTrue(new_message) + self.assertEqual(1, len(new_message)) + self.assertRegex(new_message.body, ".*Detected automatically by.*") diff --git a/iot_input_oca/tests/test_iot_multi_input.py b/iot_input_oca/tests/test_iot_multi_input.py new file mode 100644 index 00000000..0953bfc9 --- /dev/null +++ b/iot_input_oca/tests/test_iot_multi_input.py @@ -0,0 +1,174 @@ +from odoo.tests.common import SavepointCase + + +class TestIotIn(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.device_identification = "test_device_name" + cls.passphrase = "password" + cls.device = cls.env["iot.device"].create( + { + "name": "Device", + "device_identification": cls.device_identification, + "passphrase": cls.passphrase, + } + ) + 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.single_input_values = [{"input": cls.address_1, "value": "test"}] + + def test_multi_input_error_wrong_identification(self): + self.assertEqual( + self.env["iot.device"].parse_multi_input( + self.device_identification + self.device_identification, + self.passphrase, + self.single_input_values, + )["status"], + "error", + ) + + def test_multi_input_error_wrong_passphrase(self): + self.assertEqual( + self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase + self.passphrase, + self.single_input_values, + )["status"], + "error", + ) + + def test_multi_input_error_no_inputs(self): + self.assertEqual( + self.env["iot.device"].parse_multi_input( + self.device_identification, self.passphrase, False + )["status"], + "error", + ) + + def test_multi_input_non_existing_address(self): + non_existing_address = "I3" + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": non_existing_address, "value": "test value 1"}], + ): + self.assertEqual(response["status"], "error") + + def test_error_missing_parameter(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, self.passphrase, [{"address": self.address_1}] + ): + self.assertEqual(response["status"], "error") + + def test_error_with_extra_args(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": self.address_1, "uuid": "abc"}], + ): + self.assertEqual(response["status"], "error") + self.assertTrue("uuid" in response) + + def test_error_no_address_with_extra_args(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, self.passphrase, [{"uuid": "abc"}] + ): + self.assertEqual(response["status"], "error") + self.assertTrue("uuid" in response) + + def test_error_no_address(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, self.passphrase, [{"value": "test value"}] + ): + self.assertEqual(response["status"], "error") + + def test_correct_one_input(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": self.address_1, "value": "test"}], + ): + self.assertEqual(response["status"], "ok") + + def test_correct_two_inputs(self): + for response in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [ + {"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"}, + ], + ): + self.assertEqual(response["status"], "ok") + + def test_correct_with_extra_args(self): + 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 self.env["iot.device"].parse_multi_input( + self.device_identification, self.passphrase, response_with_uuid + ): + self.assertTrue(response["uuid"]) + self.assertEqual( + response["message"], + [x for x in response_with_uuid if x["uuid"] == response["uuid"]][0], + ) + + def test_error_archived_device(self): + self.device.active = False + self.assertEqual( + self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": self.address_1, "value": "test"}], + )["status"], + "error", + ) + + def test_error_archived_device_input(self): + self.device_input_1.active = False + for result in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": self.address_1, "value": "test"}], + ): + self.assertEqual( + result["status"], "error", + ) + + def test_error_archived_device_input_extra_args(self): + self.device_input_1.active = False + for result in self.env["iot.device"].parse_multi_input( + self.device_identification, + self.passphrase, + [{"address": self.address_1, "value": "test", "uuid": "ghi"}], + ): + self.assertEqual( + result["status"], "error", + ) + self.assertEqual(result["uuid"], "ghi") diff --git a/iot_input_oca/views/iot_device_input_views.xml b/iot_input_oca/views/iot_device_input_views.xml index 9cfc0a3b..cfb7b6ff 100644 --- a/iot_input_oca/views/iot_device_input_views.xml +++ b/iot_input_oca/views/iot_device_input_views.xml @@ -18,20 +18,14 @@
-
- -
+ + +

@@ -79,7 +73,6 @@ IoT Inputs ir.actions.act_window iot.device.input - form tree,form diff --git a/iot_input_oca/views/iot_device_views.xml b/iot_input_oca/views/iot_device_views.xml index 7ec80744..6a72daf4 100644 --- a/iot_input_oca/views/iot_device_views.xml +++ b/iot_input_oca/views/iot_device_views.xml @@ -3,7 +3,7 @@ iot.device.form iot.device - +

@@ -476,7 +476,7 @@

Maintainers

promote its widespread use.

Current maintainer:

etobella

-

This module is part of the OCA/iot project on GitHub.

+

This module is part of the OCA/iot project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/iot_input_oca/tests/__init__.py b/iot_input_oca/tests/__init__.py index 0740ace6..0a28a8f1 100644 --- a/iot_input_oca/tests/__init__.py +++ b/iot_input_oca/tests/__init__.py @@ -1,4 +1,3 @@ from . import test_iot_in from . import test_iot_multi_input from . import test_iot_controller -from . import test_iot_message diff --git a/iot_input_oca/tests/test_iot_controller.py b/iot_input_oca/tests/test_iot_controller.py index 083103fb..b9034d06 100644 --- a/iot_input_oca/tests/test_iot_controller.py +++ b/iot_input_oca/tests/test_iot_controller.py @@ -9,11 +9,13 @@ 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", - "device_identification": self.device_identification, - "passphrase": self.passphrase, + "communication_system_id": self.system.id, } ) self.address_1 = "I0" @@ -44,6 +46,15 @@ def setUp(self): "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( [ @@ -101,7 +112,7 @@ def test_multi_input_controller_malformed_error(self): def test_multi_input_controller(self): res = self.url_open( - "/iot/%s/multi_input" % self.device.device_identification, + "/iot/%s/multi_input" % self.device_identification, data={"passphrase": self.passphrase, "values": self.values}, ) result = res.json() diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index 602457c4..ae5cf78a 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -8,7 +8,10 @@ def setUpClass(cls): super().setUpClass() cls.serial = "testingdeviceserial" cls.passphrase = "password" - cls.device = cls.env["iot.device"].create({"name": "Device"}) + 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", diff --git a/iot_input_oca/tests/test_iot_message.py b/iot_input_oca/tests/test_iot_message.py deleted file mode 100644 index 8ea97678..00000000 --- a/iot_input_oca/tests/test_iot_message.py +++ /dev/null @@ -1,46 +0,0 @@ -from odoo_test_helper import FakeModelLoader - -from odoo.tests import SavepointCase - - -class TestIotInputMessage(SavepointCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.loader = FakeModelLoader(cls.env, cls.__module__) - cls.loader.backup_registry() - - from .models import ResPartner - - cls.loader.update_registry((ResPartner,)) - - cls.partner = cls.env["res.partner"].create({"name": "IoT demo partner"}) - cls.serial = "testingdeviceserial" - cls.passphrase = "password" - cls.device = cls.env["iot.device"].create({"name": "Device"}) - 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("base.model_res_partner").id, - "call_function": "test_fake_iot_input", - } - ) - cls.iot = cls.env["iot.device.input"] - - @classmethod - def tearDownClass(cls): - cls.loader.restore_registry() - super().tearDownClass() - - def test_message(self): - original_messages = self.partner.message_ids - res = self.device_input.call_device(value=self.partner.id) - self.assertEqual("ok", res["status"]) - new_message = self.partner.message_ids - original_messages - self.assertTrue(new_message) - self.assertEqual(1, len(new_message)) - self.assertRegex(new_message.body, ".*Detected automatically by.*") diff --git a/iot_input_oca/tests/test_iot_multi_input.py b/iot_input_oca/tests/test_iot_multi_input.py index d33dadbd..61958d4f 100644 --- a/iot_input_oca/tests/test_iot_multi_input.py +++ b/iot_input_oca/tests/test_iot_multi_input.py @@ -8,11 +8,12 @@ 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", - "device_identification": cls.device_identification, - "passphrase": cls.passphrase, + "communication_system_id": cls.system.id, } ) cls.address_1 = "I0" @@ -35,88 +36,97 @@ def setUpClass(cls): "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): - self.assertEqual( - self.env["iot.device"].parse_multi_input( - self.device_identification + self.device_identification, - self.passphrase, - self.single_input_values, - )["status"], - "error", + def remove_test_multi_input_error_wrong_identification(self): + iot = self.iot.get_device( + serial=self.device_identification + self.device_identification, + passphrase=self.passphrase, ) - - def test_multi_input_error_wrong_passphrase(self): self.assertEqual( - self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase + self.passphrase, - self.single_input_values, - )["status"], - "error", + iot.call_device(values=self.single_input_values)["status"], + "ko", ) def test_multi_input_error_no_inputs(self): + iot = self.iot.get_device( + serial=self.device_identification, passphrase=self.passphrase + ) self.assertEqual( - self.env["iot.device"].parse_multi_input( - self.device_identification, self.passphrase, False - )["status"], - "error", + iot.call_device(values=[])["status"], + "ko", ) def test_multi_input_non_existing_address(self): non_existing_address = "I3" - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": non_existing_address, "value": "test value 1"}], - ): + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, self.passphrase, [{"address": self.address_1}] - ): + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": self.address_1, "uuid": "abc"}], - ): + + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, self.passphrase, [{"uuid": "abc"}] - ): + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, self.passphrase, [{"value": "test value"}] - ): + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": self.address_1, "value": "test"}], - ): + 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): - for response in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [ + 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, @@ -124,18 +134,19 @@ def test_correct_two_inputs(self): }, # 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 self.env["iot.device"].parse_multi_input( - self.device_identification, self.passphrase, response_with_uuid - ): + for response in iot.call_device(values=response_with_uuid)["result"]: self.assertTrue(response["uuid"]) self.assertEqual( response["message"], @@ -146,22 +157,24 @@ def test_correct_with_extra_args(self): def test_error_archived_device(self): self.device.active = False + iot = self.iot.get_device( + serial=self.device_identification, passphrase=self.passphrase + ) self.assertEqual( - self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": self.address_1, "value": "test"}], + 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 - for result in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": self.address_1, "value": "test"}], - ): + 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", @@ -169,11 +182,12 @@ def test_error_archived_device_input(self): def test_error_archived_device_input_extra_args(self): self.device_input_1.active = False - for result in self.env["iot.device"].parse_multi_input( - self.device_identification, - self.passphrase, - [{"address": self.address_1, "value": "test", "uuid": "ghi"}], - ): + 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", diff --git a/iot_input_oca/views/iot_device_input_views.xml b/iot_input_oca/views/iot_device_input_views.xml index cfb7b6ff..05e9ef32 100644 --- a/iot_input_oca/views/iot_device_input_views.xml +++ b/iot_input_oca/views/iot_device_input_views.xml @@ -53,6 +53,7 @@ iot.device.input + Date: Wed, 11 May 2022 10:40:19 +0200 Subject: [PATCH 11/31] [MIG] iot_input_oca: Migration to 15.0 --- iot_input_oca/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 1c1ffe87..4b8f7fc0 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "IoT Input", - "version": "14.0.1.0.0", + "version": "15.0.1.0.0", "category": "IoT", "author": "Creu Blanca, Odoo Community Association (OCA)", "license": "AGPL-3", From c3f0738a16619131ea0071070c72356595821d73 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 12 May 2022 07:57:43 +0000 Subject: [PATCH 12/31] [UPD] Update iot_input_oca.pot --- iot_input_oca/i18n/iot_input_oca.pot | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iot_input_oca/i18n/iot_input_oca.pot b/iot_input_oca/i18n/iot_input_oca.pot index 23932f11..47a07445 100644 --- a/iot_input_oca/i18n/iot_input_oca.pot +++ b/iot_input_oca/i18n/iot_input_oca.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -96,14 +96,12 @@ msgid "Device input" msgstr "" #. module: iot_input_oca -#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__display_name #: 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__id #: 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" @@ -156,7 +154,6 @@ msgid "Language" msgstr "" #. module: iot_input_oca -#: model:ir.model.fields,field_description:iot_input_oca.field_iot_device____last_update #: 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" From 6fc67d1fc1bf5006d3c55179063cbaa6e45b82b3 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 12 May 2022 08:00:01 +0000 Subject: [PATCH 13/31] [UPD] README.rst --- iot_input_oca/README.rst | 10 +++++----- iot_input_oca/static/description/index.html | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index 7fb7e3f4..439a4538 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -14,13 +14,13 @@ IoT Input :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/14.0/iot_input_oca + :target: https://github.com/OCA/iot/tree/15.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-14-0/iot-14-0-iot_input_oca + :target: https://translation.odoo-community.org/projects/iot-15-0/iot-15-0-iot_input_oca :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/269/14.0 + :target: https://runbot.odoo-community.org/runbot/269/15.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -110,7 +110,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -149,6 +149,6 @@ Current `maintainer `__: |maintainer-etobella| -This module is part of the `OCA/iot `_ project on GitHub. +This module is part of the `OCA/iot `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index 12d9529f..6ef640ba 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -367,7 +367,7 @@

IoT Input

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

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.

@@ -449,7 +449,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -476,7 +476,7 @@

Maintainers

promote its widespread use.

Current maintainer:

etobella

-

This module is part of the OCA/iot project on GitHub.

+

This module is part of the OCA/iot project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 2b00e55e526dc73cd2ef854edf1afc7c5f4b9095 Mon Sep 17 00:00:00 2001 From: jabelchi Date: Fri, 3 Jun 2022 08:30:16 +0000 Subject: [PATCH 14/31] Added translation using Weblate (Catalan) --- iot_input_oca/i18n/ca.po | 236 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 iot_input_oca/i18n/ca.po diff --git a/iot_input_oca/i18n/ca.po b/iot_input_oca/i18n/ca.po new file mode 100644 index 00000000..7b20df70 --- /dev/null +++ b/iot_input_oca/i18n/ca.po @@ -0,0 +1,236 @@ +# 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" +"Last-Translator: Automatically generated\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" + +#. module: iot_input_oca +#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban +msgid "" +"\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 +#: 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 +#: 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 +#: 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 +#: code:addons/iot_input_oca/models/iot_device_input.py:0 +#, python-format +msgid "Serial and passphrase are required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Server Error" +msgstr "" + +#. module: iot_input_oca +#: 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 +#: 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 +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values is required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values should be a JSON array of JSON objects" +msgstr "" From 499287adb435c6c922212a42bb53474dafd2441a Mon Sep 17 00:00:00 2001 From: jabelchi Date: Fri, 3 Jun 2022 08:36:51 +0000 Subject: [PATCH 15/31] Translated using Weblate (Catalan) Currently translated at 87.5% (35 of 40 strings) Translation: iot-15.0/iot-15.0-iot_input_oca Translate-URL: https://translation.odoo-community.org/projects/iot-15-0/iot-15-0-iot_input_oca/ca/ --- iot_input_oca/i18n/ca.po | 74 +++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/iot_input_oca/i18n/ca.po b/iot_input_oca/i18n/ca.po index 7b20df70..9e417cae 100644 --- a/iot_input_oca/i18n/ca.po +++ b/iot_input_oca/i18n/ca.po @@ -6,13 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2022-06-03 11:05+0000\n" +"Last-Translator: jabelchi \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 @@ -24,44 +26,44 @@ msgstr "" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids msgid "Action" -msgstr "" +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 "" +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 "" +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 "" +msgstr "Actiu" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address msgid "Address" -msgstr "" +msgstr "Adreça" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device.py:0 #, python-format msgid "Address for Input is required" -msgstr "" +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 "" +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 "" +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 @@ -72,121 +74,121 @@ msgstr "" #: 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 "" +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 "" +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 "" +msgstr "Dispositiu" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device_input.py:0 #, python-format msgid "Device cannot be found" -msgstr "" +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 "" +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 "" +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 "" +msgstr "ID" #. module: iot_input_oca #: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search msgid "Inactive" -msgstr "" +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 "" +msgstr "Entrada" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count msgid "Input Count" -msgstr "" +msgstr "Nombre d'entrades" #. module: iot_input_oca #: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form msgid "Inputs" -msgstr "" +msgstr "Entrades" #. module: iot_input_oca #: model:ir.model,name:iot_input_oca.model_iot_device msgid "IoT Device" -msgstr "" +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 "" +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 "" +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 "" +msgstr "Kwargs" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang msgid "Language" -msgstr "" +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 "" +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 "" +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 "" +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 "" +msgstr "Nom" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase msgid "Passphrase" -msgstr "" +msgstr "Contrasenya" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Passphrase is required" -msgstr "" +msgstr "Es requereix contrasenya" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input_action__res @@ -196,32 +198,32 @@ msgstr "" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial msgid "Serial" -msgstr "" +msgstr "Número de sèrie" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device_input.py:0 #, python-format msgid "Serial and passphrase are required" -msgstr "" +msgstr "Es requereix número de sèrie i contrasenya" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Server Error" -msgstr "" +msgstr "Error de servidor" #. module: iot_input_oca #: 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 "" +msgstr "Error de servidor. Comproveu els registres del servidor" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Values is not a valid JSON" -msgstr "" +msgstr "El valor no és un JSON vàlid" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 From e6243eb8142aebcab9f91101d222345986db2177 Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 23 Mar 2023 07:03:42 +0000 Subject: [PATCH 16/31] Added translation using Weblate (Italian) --- iot_input_oca/i18n/it.po | 236 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 iot_input_oca/i18n/it.po diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po new file mode 100644 index 00000000..81f8c482 --- /dev/null +++ b/iot_input_oca/i18n/it.po @@ -0,0 +1,236 @@ +# 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" +"Last-Translator: Automatically generated\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" + +#. module: iot_input_oca +#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban +msgid "" +"\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 +#: 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 +#: 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 +#: 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 +#: code:addons/iot_input_oca/models/iot_device_input.py:0 +#, python-format +msgid "Serial and passphrase are required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Server Error" +msgstr "" + +#. module: iot_input_oca +#: 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 +#: 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 +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values is required" +msgstr "" + +#. module: iot_input_oca +#: code:addons/iot_input_oca/controller/iot_input_controller.py:0 +#, python-format +msgid "Values should be a JSON array of JSON objects" +msgstr "" From 1fdbea45fa87d58123921bf3ab192d45267ae6b2 Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 23 Mar 2023 10:38:59 +0000 Subject: [PATCH 17/31] Translated using Weblate (Italian) Currently translated at 100.0% (40 of 40 strings) Translation: iot-15.0/iot-15.0-iot_input_oca Translate-URL: https://translation.odoo-community.org/projects/iot-15-0/iot-15-0-iot_input_oca/it/ --- iot_input_oca/i18n/it.po | 84 +++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po index 81f8c482..01c46dfc 100644 --- a/iot_input_oca/i18n/it.po +++ b/iot_input_oca/i18n/it.po @@ -6,13 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2023-03-23 13:23+0000\n" +"Last-Translator: mymage \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 4.14.1\n" #. module: iot_input_oca #: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban @@ -20,217 +22,219 @@ msgid "" "\n" " Inputs" msgstr "" +"\n" +" Input" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__action_ids msgid "Action" -msgstr "" +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 "" +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 "" +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 "" +msgstr "Attivo" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address msgid "Address" -msgstr "" +msgstr "indirizzo" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device.py:0 #, python-format msgid "Address for Input is required" -msgstr "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +msgstr "Dispositivo" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device_input.py:0 #, python-format msgid "Device cannot be found" -msgstr "" +msgstr "Non si può trovare il dispositivo" #. module: iot_input_oca #: model:ir.model,name:iot_input_oca.model_iot_device_input msgid "Device input" -msgstr "" +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 "" +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 "" +msgstr "ID" #. module: iot_input_oca #: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_input_search msgid "Inactive" -msgstr "" +msgstr "Non attivo" #. 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 "" +msgstr "Input" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device__input_count msgid "Input Count" -msgstr "" +msgstr "Conteggio input" #. module: iot_input_oca #: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_form msgid "Inputs" -msgstr "" +msgstr "Input" #. module: iot_input_oca #: model:ir.model,name:iot_input_oca.model_iot_device msgid "IoT Device" -msgstr "" +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 "" +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 "" +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 "" +msgstr "Kwargs" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__lang msgid "Language" -msgstr "" +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 "" +msgstr "Ultima modica 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 "" +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 "" +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 "" +msgstr "Nome" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__passphrase msgid "Passphrase" -msgstr "" +msgstr "Passphrase" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Passphrase is required" -msgstr "" +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 "" +msgstr "Res" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__serial msgid "Serial" -msgstr "" +msgstr "Seriale" #. module: iot_input_oca #: code:addons/iot_input_oca/models/iot_device_input.py:0 #, python-format msgid "Serial and passphrase are required" -msgstr "" +msgstr "Richiesti seriale e passphrase" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Server Error" -msgstr "" +msgstr "Errore server" #. module: iot_input_oca #: 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 "" +msgstr "Errore server: Controllare i log del server" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Values is not a valid JSON" -msgstr "" +msgstr "I valori non sono in formato JSON" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Values is required" -msgstr "" +msgstr "Richiesti valori" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 #, python-format msgid "Values should be a JSON array of JSON objects" -msgstr "" +msgstr "I valori devono essere una matrice o un oggetto JSON" From 442b6b495e767dc86c3fb84dabdafa37e6fa9c66 Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 23 Mar 2023 14:38:22 +0000 Subject: [PATCH 18/31] Translated using Weblate (Italian) Currently translated at 100.0% (40 of 40 strings) Translation: iot-15.0/iot-15.0-iot_input_oca Translate-URL: https://translation.odoo-community.org/projects/iot-15-0/iot-15-0-iot_input_oca/it/ --- iot_input_oca/i18n/it.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po index 01c46dfc..26f44cd5 100644 --- a/iot_input_oca/i18n/it.po +++ b/iot_input_oca/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-03-23 13:23+0000\n" +"PO-Revision-Date: 2023-03-23 16:34+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -93,7 +93,7 @@ msgstr "Dispositivo" #: code:addons/iot_input_oca/models/iot_device_input.py:0 #, python-format msgid "Device cannot be found" -msgstr "Non si può trovare il dispositivo" +msgstr "Dispositivo non trovato" #. module: iot_input_oca #: model:ir.model,name:iot_input_oca.model_iot_device_input @@ -219,7 +219,7 @@ msgstr "Errore server" #: 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" +msgstr "Errore server: controllare i log del server" #. module: iot_input_oca #: code:addons/iot_input_oca/controller/iot_input_controller.py:0 From 8030877e10b31aeee447a220ae431c0a3ef4d0a4 Mon Sep 17 00:00:00 2001 From: maso Date: Wed, 14 Jun 2023 21:38:51 +0330 Subject: [PATCH 19/31] [MIG] iot_input_oca: Migration to 16.0 --- iot_input_oca/__manifest__.py | 4 ++-- iot_input_oca/i18n/it.po | 4 ++-- .../migrations/14.0.1.0.0/post-migration.py | 24 ------------------- iot_input_oca/tests/test_iot_controller.py | 8 +++++++ iot_input_oca/tests/test_iot_in.py | 24 +++++++++++++++++++ iot_input_oca/tests/test_iot_multi_input.py | 5 ++-- 6 files changed, 39 insertions(+), 30 deletions(-) delete mode 100644 iot_input_oca/migrations/14.0.1.0.0/post-migration.py diff --git a/iot_input_oca/__manifest__.py b/iot_input_oca/__manifest__.py index 4b8f7fc0..ab43daaa 100644 --- a/iot_input_oca/__manifest__.py +++ b/iot_input_oca/__manifest__.py @@ -2,9 +2,9 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "IoT Input", - "version": "15.0.1.0.0", - "category": "IoT", + "version": "16.0.1.0.0", "author": "Creu Blanca, Odoo Community Association (OCA)", + "category": "IoT", "license": "AGPL-3", "installable": True, "summary": "IoT Input module", diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po index 26f44cd5..58956961 100644 --- a/iot_input_oca/i18n/it.po +++ b/iot_input_oca/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-03-23 16:34+0000\n" +"PO-Revision-Date: 2023-03-30 15:22+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -162,7 +162,7 @@ msgstr "Lingua" #: 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 modica il" +msgstr "Ultima modifica il" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__write_uid diff --git a/iot_input_oca/migrations/14.0.1.0.0/post-migration.py b/iot_input_oca/migrations/14.0.1.0.0/post-migration.py deleted file mode 100644 index f9b457b2..00000000 --- a/iot_input_oca/migrations/14.0.1.0.0/post-migration.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2021 Creu Blanca -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - openupgrade.logged_query( - env.cr, - """SELECT id, device_identification, passphrase - FROM iot_device - WHERE device_identification IS NOT NULL""", - ) - res = env.cr.fetchall() - for device_id, serial, passphrase in res: - env["iot.device.input"].create( - { - "device_id": device_id, - "serial": serial, - "passphrase": passphrase, - "name": "Multi value input - Generated on Migration", - "call_function": "parse_multi_input", - } - ) diff --git a/iot_input_oca/tests/test_iot_controller.py b/iot_input_oca/tests/test_iot_controller.py index b9034d06..a75da83d 100644 --- a/iot_input_oca/tests/test_iot_controller.py +++ b/iot_input_oca/tests/test_iot_controller.py @@ -82,6 +82,14 @@ def test_single_controller_archived_device(self): ) 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, diff --git a/iot_input_oca/tests/test_iot_in.py b/iot_input_oca/tests/test_iot_in.py index ae5cf78a..63136880 100644 --- a/iot_input_oca/tests/test_iot_in.py +++ b/iot_input_oca/tests/test_iot_in.py @@ -96,3 +96,27 @@ def test_device_input_calling(self): 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}) diff --git a/iot_input_oca/tests/test_iot_multi_input.py b/iot_input_oca/tests/test_iot_multi_input.py index 61958d4f..f4afe2d9 100644 --- a/iot_input_oca/tests/test_iot_multi_input.py +++ b/iot_input_oca/tests/test_iot_multi_input.py @@ -48,14 +48,15 @@ def setUpClass(cls): cls.single_input_values = [{"input": cls.address_1, "value": "test"}] cls.iot = cls.env["iot.device.input"] - def remove_test_multi_input_error_wrong_identification(self): + 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"], - "ko", + "error", ) def test_multi_input_error_no_inputs(self): From bfe9b2a9c6799f29cf36c16c4dd445c1f43d9711 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 15 Jun 2023 13:06:48 +0000 Subject: [PATCH 20/31] [UPD] Update iot_input_oca.pot --- iot_input_oca/i18n/iot_input_oca.pot | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/iot_input_oca/i18n/iot_input_oca.pot b/iot_input_oca/i18n/iot_input_oca.pot index 47a07445..aea720c9 100644 --- a/iot_input_oca/i18n/iot_input_oca.pot +++ b/iot_input_oca/i18n/iot_input_oca.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 15.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -47,6 +47,7 @@ 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" @@ -85,6 +86,7 @@ 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" @@ -182,6 +184,7 @@ 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" @@ -198,18 +201,21 @@ 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 @@ -217,18 +223,21 @@ 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" From a00b2fb9e7d6e44c087f7f18560187571dbe5911 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 15 Jun 2023 13:09:09 +0000 Subject: [PATCH 21/31] [UPD] README.rst --- iot_input_oca/README.rst | 10 +++++----- iot_input_oca/static/description/index.html | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index 439a4538..2be791b5 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -14,13 +14,13 @@ IoT Input :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/15.0/iot_input_oca + :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-15-0/iot-15-0-iot_input_oca + :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/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/269/15.0 + :target: https://runbot.odoo-community.org/runbot/269/16.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -110,7 +110,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -149,6 +149,6 @@ Current `maintainer `__: |maintainer-etobella| -This module is part of the `OCA/iot `_ project on GitHub. +This module is part of the `OCA/iot `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index 6ef640ba..236c6523 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -367,7 +367,7 @@

IoT Input

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/iot Translate me on Weblate Try me on Runbot

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.

@@ -449,7 +449,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -476,7 +476,7 @@

Maintainers

promote its widespread use.

Current maintainer:

etobella

-

This module is part of the OCA/iot project on GitHub.

+

This module is part of the OCA/iot project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 4bc43cf2649dc1e68dbe53fd81012d9f40ac59f5 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 15 Jun 2023 15:15:01 +0000 Subject: [PATCH 22/31] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: iot-16.0/iot-16.0-iot_input_oca Translate-URL: https://translation.odoo-community.org/projects/iot-16-0/iot-16-0-iot_input_oca/ --- iot_input_oca/i18n/ca.po | 10 +++++++++- iot_input_oca/i18n/it.po | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/iot_input_oca/i18n/ca.po b/iot_input_oca/i18n/ca.po index 9e417cae..908e39af 100644 --- a/iot_input_oca/i18n/ca.po +++ b/iot_input_oca/i18n/ca.po @@ -50,6 +50,7 @@ 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" @@ -88,6 +89,7 @@ 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" @@ -185,6 +187,7 @@ 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" @@ -201,37 +204,42 @@ 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 -#: code:addons/iot_input_oca/models/iot_device.py:0 +#. 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" diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po index 58956961..4005d7e4 100644 --- a/iot_input_oca/i18n/it.po +++ b/iot_input_oca/i18n/it.po @@ -52,6 +52,7 @@ 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" @@ -90,6 +91,7 @@ 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" @@ -187,6 +189,7 @@ 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" @@ -203,37 +206,42 @@ 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 -#: code:addons/iot_input_oca/models/iot_device.py:0 +#. 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" From 55c4b137211dd30650688ff3765308a9a9bd1ed8 Mon Sep 17 00:00:00 2001 From: mymage Date: Tue, 18 Jul 2023 10:26:03 +0000 Subject: [PATCH 23/31] Translated using Weblate (Italian) Currently translated at 100.0% (40 of 40 strings) Translation: iot-16.0/iot-16.0-iot_input_oca Translate-URL: https://translation.odoo-community.org/projects/iot-16-0/iot-16-0-iot_input_oca/it/ --- iot_input_oca/i18n/it.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iot_input_oca/i18n/it.po b/iot_input_oca/i18n/it.po index 4005d7e4..1d69289a 100644 --- a/iot_input_oca/i18n/it.po +++ b/iot_input_oca/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-03-30 15:22+0000\n" +"PO-Revision-Date: 2023-07-18 13:11+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.14.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 @@ -49,7 +49,7 @@ msgstr "Attivo" #. module: iot_input_oca #: model:ir.model.fields,field_description:iot_input_oca.field_iot_device_input__address msgid "Address" -msgstr "indirizzo" +msgstr "Indirizzo" #. module: iot_input_oca #. odoo-python From 3aa972b37d6bef0bdb594cc90a4d4ee975294337 Mon Sep 17 00:00:00 2001 From: Ivorra78 Date: Tue, 22 Aug 2023 14:07:18 +0000 Subject: [PATCH 24/31] Added translation using Weblate (Spanish) --- iot_input_oca/i18n/es.po | 245 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 iot_input_oca/i18n/es.po diff --git a/iot_input_oca/i18n/es.po b/iot_input_oca/i18n/es.po new file mode 100644 index 00000000..4a14310c --- /dev/null +++ b/iot_input_oca/i18n/es.po @@ -0,0 +1,245 @@ +# 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: Automatically generated\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" + +#. module: iot_input_oca +#: model_terms:ir.ui.view,arch_db:iot_input_oca.iot_device_kanban +msgid "" +"\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 "" From 64cbb3353782e2266136ce9eab42519794573bce Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sun, 3 Sep 2023 13:18:05 +0000 Subject: [PATCH 25/31] [UPD] README.rst --- iot_input_oca/README.rst | 15 ++++---- iot_input_oca/static/description/index.html | 40 +++++++++++---------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/iot_input_oca/README.rst b/iot_input_oca/README.rst index 2be791b5..5115f37f 100644 --- a/iot_input_oca/README.rst +++ b/iot_input_oca/README.rst @@ -2,10 +2,13 @@ IoT Input ========= -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:e659667d71381159c522d2752013f4cb6047702bc458f1715e0e9655ca0414f7 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ IoT Input .. |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/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/269/16.0 - :alt: Try me on Runbot +.. |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| +|badge1| |badge2| |badge3| |badge4| |badge5| This addon allows to use a device in order to input data to odoo automatically. @@ -109,7 +112,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed +If you spotted it first, help us to smash it by providing a detailed and welcomed `feedback `_. Do not contact contributors directly about support or help with technical issues. diff --git a/iot_input_oca/static/description/index.html b/iot_input_oca/static/description/index.html index 236c6523..e54b3c0e 100644 --- a/iot_input_oca/static/description/index.html +++ b/iot_input_oca/static/description/index.html @@ -1,20 +1,20 @@ - + - + IoT Input