summaryrefslogtreecommitdiff
path: root/addons/hw_posbox_homepage
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/hw_posbox_homepage
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/hw_posbox_homepage')
-rw-r--r--addons/hw_posbox_homepage/__init__.py4
-rw-r--r--addons/hw_posbox_homepage/__manifest__.py24
-rw-r--r--addons/hw_posbox_homepage/controllers/__init__.py4
-rw-r--r--addons/hw_posbox_homepage/controllers/main.py359
-rw-r--r--addons/hw_posbox_homepage/views/configure_wizard.html180
-rw-r--r--addons/hw_posbox_homepage/views/handler_list.html50
-rw-r--r--addons/hw_posbox_homepage/views/homepage.html152
-rw-r--r--addons/hw_posbox_homepage/views/layout.html143
-rw-r--r--addons/hw_posbox_homepage/views/list_credential.html68
-rw-r--r--addons/hw_posbox_homepage/views/loading.html14
-rw-r--r--addons/hw_posbox_homepage/views/remote_connect.html42
-rw-r--r--addons/hw_posbox_homepage/views/server_config.html60
-rw-r--r--addons/hw_posbox_homepage/views/six_payment_terminal.html61
-rw-r--r--addons/hw_posbox_homepage/views/upgrade_page.html95
-rw-r--r--addons/hw_posbox_homepage/views/wifi_config.html71
15 files changed, 1327 insertions, 0 deletions
diff --git a/addons/hw_posbox_homepage/__init__.py b/addons/hw_posbox_homepage/__init__.py
new file mode 100644
index 00000000..dd15b5c3
--- /dev/null
+++ b/addons/hw_posbox_homepage/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import controllers
diff --git a/addons/hw_posbox_homepage/__manifest__.py b/addons/hw_posbox_homepage/__manifest__.py
new file mode 100644
index 00000000..f10464ea
--- /dev/null
+++ b/addons/hw_posbox_homepage/__manifest__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'IoT Box Homepage',
+ 'category': 'Sales/Point of Sale',
+ 'sequence': 6,
+ 'website': 'https://www.odoo.com/page/point-of-sale-hardware',
+ 'summary': 'A homepage for the IoT Box',
+ 'description': """
+IoT Box Homepage
+================
+
+This module overrides Odoo web interface to display a simple
+Homepage that explains what's the iotbox and shows the status,
+and where to find documentation.
+
+If you activate this module, you won't be able to access the
+regular Odoo interface anymore.
+
+""",
+ 'installable': False,
+ 'license': 'LGPL-3',
+}
diff --git a/addons/hw_posbox_homepage/controllers/__init__.py b/addons/hw_posbox_homepage/controllers/__init__.py
new file mode 100644
index 00000000..5d4b25db
--- /dev/null
+++ b/addons/hw_posbox_homepage/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import main
diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py
new file mode 100644
index 00000000..146860cf
--- /dev/null
+++ b/addons/hw_posbox_homepage/controllers/main.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import json
+import jinja2
+import logging
+import os
+from pathlib import Path
+import socket
+import subprocess
+import sys
+import threading
+
+from odoo import http
+from odoo.http import Response
+from odoo.modules.module import get_resource_path
+
+from odoo.addons.hw_drivers.main import iot_devices
+from odoo.addons.hw_drivers.tools import helpers
+from odoo.addons.web.controllers import main as web
+
+_logger = logging.getLogger(__name__)
+
+
+#----------------------------------------------------------
+# Controllers
+#----------------------------------------------------------
+
+if hasattr(sys, 'frozen'):
+ # When running on compiled windows binary, we don't have access to package loader.
+ path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views'))
+ loader = jinja2.FileSystemLoader(path)
+else:
+ loader = jinja2.PackageLoader('odoo.addons.hw_posbox_homepage', "views")
+
+jinja_env = jinja2.Environment(loader=loader, autoescape=True)
+jinja_env.filters["json"] = json.dumps
+
+homepage_template = jinja_env.get_template('homepage.html')
+server_config_template = jinja_env.get_template('server_config.html')
+wifi_config_template = jinja_env.get_template('wifi_config.html')
+handler_list_template = jinja_env.get_template('handler_list.html')
+remote_connect_template = jinja_env.get_template('remote_connect.html')
+configure_wizard_template = jinja_env.get_template('configure_wizard.html')
+six_payment_terminal_template = jinja_env.get_template('six_payment_terminal.html')
+list_credential_template = jinja_env.get_template('list_credential.html')
+upgrade_page_template = jinja_env.get_template('upgrade_page.html')
+
+class IoTboxHomepage(web.Home):
+ def __init__(self):
+ super(IoTboxHomepage,self).__init__()
+ self.updating = threading.Lock()
+
+ def clean_partition(self):
+ subprocess.check_call(['sudo', 'bash', '-c', '. /home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/upgrade.sh; cleanup'])
+
+ def get_six_terminal(self):
+ terminal_id = helpers.read_file_first_line('odoo-six-payment-terminal.conf')
+ return terminal_id or 'Not Configured'
+
+ def get_homepage_data(self):
+ hostname = str(socket.gethostname())
+ ssid = helpers.get_ssid()
+ wired = subprocess.check_output(['cat', '/sys/class/net/eth0/operstate']).decode('utf-8').strip('\n')
+ if wired == 'up':
+ network = 'Ethernet'
+ elif ssid:
+ if helpers.access_point():
+ network = 'Wifi access point'
+ else:
+ network = 'Wifi : ' + ssid
+ else:
+ network = 'Not Connected'
+
+ iot_device = []
+ for device in iot_devices:
+ iot_device.append({
+ 'name': iot_devices[device].device_name + ' : ' + str(iot_devices[device].data['value']),
+ 'type': iot_devices[device].device_type.replace('_', ' '),
+ 'identifier': iot_devices[device].device_identifier,
+ })
+
+ return {
+ 'hostname': hostname,
+ 'ip': helpers.get_ip(),
+ 'mac': helpers.get_mac_address(),
+ 'iot_device_status': iot_device,
+ 'server_status': helpers.get_odoo_server_url() or 'Not Configured',
+ 'six_terminal': self.get_six_terminal(),
+ 'network_status': network,
+ 'version': helpers.get_version(),
+ }
+
+ @http.route('/', type='http', auth='none')
+ def index(self):
+ wifi = Path.home() / 'wifi_network.txt'
+ remote_server = Path.home() / 'odoo-remote-server.conf'
+ if (wifi.exists() == False or remote_server.exists() == False) and helpers.access_point():
+ return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069/steps'>"
+ else:
+ return homepage_template.render(self.get_homepage_data())
+
+ @http.route('/list_handlers', type='http', auth='none', website=True)
+ def list_handlers(self):
+ drivers_list = []
+ for driver in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/drivers')):
+ if driver != '__pycache__':
+ drivers_list.append(driver)
+ interfaces_list = []
+ for interface in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/interfaces')):
+ if interface != '__pycache__':
+ interfaces_list.append(interface)
+ return handler_list_template.render({
+ 'title': "Odoo's IoT Box - Handlers list",
+ 'breadcrumb': 'Handlers list',
+ 'drivers_list': drivers_list,
+ 'interfaces_list': interfaces_list,
+ 'server': helpers.get_odoo_server_url()
+ })
+
+ @http.route('/load_iot_handlers', type='http', auth='none', website=True)
+ def load_iot_handlers(self):
+ helpers.download_iot_handlers(False)
+ subprocess.check_call(["sudo", "service", "odoo", "restart"])
+ return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069/list_handlers'>"
+
+ @http.route('/list_credential', type='http', auth='none', website=True)
+ def list_credential(self):
+ return list_credential_template.render({
+ 'title': "Odoo's IoT Box - List credential",
+ 'breadcrumb': 'List credential',
+ 'db_uuid': helpers.read_file_first_line('odoo-db-uuid.conf'),
+ 'enterprise_code': helpers.read_file_first_line('odoo-enterprise-code.conf'),
+ })
+
+ @http.route('/save_credential', type='http', auth='none', cors='*', csrf=False)
+ def save_credential(self, db_uuid, enterprise_code):
+ helpers.add_credential(db_uuid, enterprise_code)
+ subprocess.check_call(["sudo", "service", "odoo", "restart"])
+ return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069'>"
+
+ @http.route('/clear_credential', type='http', auth='none', cors='*', csrf=False)
+ def clear_credential(self):
+ helpers.unlink_file('odoo-db-uuid.conf')
+ helpers.unlink_file('odoo-enterprise-code.conf')
+ subprocess.check_call(["sudo", "service", "odoo", "restart"])
+ return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069'>"
+
+ @http.route('/wifi', type='http', auth='none', website=True)
+ def wifi(self):
+ return wifi_config_template.render({
+ 'title': 'Wifi configuration',
+ 'breadcrumb': 'Configure Wifi',
+ 'loading_message': 'Connecting to Wifi',
+ 'ssid': helpers.get_wifi_essid(),
+ })
+
+ @http.route('/wifi_connect', type='http', auth='none', cors='*', csrf=False)
+ def connect_to_wifi(self, essid, password, persistent=False):
+ if persistent:
+ persistent = "1"
+ else:
+ persistent = ""
+
+ subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_wifi.sh'), essid, password, persistent])
+ server = helpers.get_odoo_server_url()
+ res_payload = {
+ 'message': 'Connecting to ' + essid,
+ }
+ if server:
+ res_payload['server'] = {
+ 'url': server,
+ 'message': 'Redirect to Odoo Server'
+ }
+ else:
+ res_payload['server'] = {
+ 'url': 'http://' + helpers.get_ip() + ':8069',
+ 'message': 'Redirect to IoT Box'
+ }
+
+ return json.dumps(res_payload)
+
+ @http.route('/wifi_clear', type='http', auth='none', cors='*', csrf=False)
+ def clear_wifi_configuration(self):
+ helpers.unlink_file('wifi_network.txt')
+ return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069'>"
+
+ @http.route('/server_clear', type='http', auth='none', cors='*', csrf=False)
+ def clear_server_configuration(self):
+ helpers.unlink_file('odoo-remote-server.conf')
+ return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069'>"
+
+ @http.route('/handlers_clear', type='http', auth='none', cors='*', csrf=False)
+ def clear_handlers_list(self):
+ for directory in ['drivers', 'interfaces']:
+ for file in os.listdir(get_resource_path('hw_drivers', 'iot_handlers', directory)):
+ if file != '__pycache__':
+ helpers.unlink_file(get_resource_path('hw_drivers', 'iot_handlers', directory, file))
+ return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069/list_handlers'>"
+
+ @http.route('/server_connect', type='http', auth='none', cors='*', csrf=False)
+ def connect_to_server(self, token, iotname):
+ if token:
+ credential = token.split('|')
+ url = credential[0]
+ token = credential[1]
+ if len(credential) > 2:
+ # IoT Box send token with db_uuid and enterprise_code only since V13
+ db_uuid = credential[2]
+ enterprise_code = credential[3]
+ helpers.add_credential(db_uuid, enterprise_code)
+ else:
+ url = helpers.get_odoo_server_url()
+ token = helpers.get_token()
+ reboot = 'reboot'
+ subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, iotname, token, reboot])
+ return 'http://' + helpers.get_ip() + ':8069'
+
+ @http.route('/steps', type='http', auth='none', cors='*', csrf=False)
+ def step_by_step_configure_page(self):
+ return configure_wizard_template.render({
+ 'title': 'Configure IoT Box',
+ 'breadcrumb': 'Configure IoT Box',
+ 'loading_message': 'Configuring your IoT Box',
+ 'ssid': helpers.get_wifi_essid(),
+ 'server': helpers.get_odoo_server_url() or '',
+ 'hostname': subprocess.check_output('hostname').decode('utf-8').strip('\n'),
+ })
+
+ @http.route('/step_configure', type='http', auth='none', cors='*', csrf=False)
+ def step_by_step_configure(self, token, iotname, essid, password, persistent=False):
+ if token:
+ url = token.split('|')[0]
+ token = token.split('|')[1]
+ else:
+ url = ''
+ subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server_wifi.sh'), url, iotname, token, essid, password, persistent])
+ return url
+
+ # Set server address
+ @http.route('/server', type='http', auth='none', website=True)
+ def server(self):
+ return server_config_template.render({
+ 'title': 'IoT -> Odoo server configuration',
+ 'breadcrumb': 'Configure Odoo Server',
+ 'hostname': subprocess.check_output('hostname').decode('utf-8').strip('\n'),
+ 'server_status': helpers.get_odoo_server_url() or 'Not configured yet',
+ 'loading_message': 'Configure Domain Server'
+ })
+
+ @http.route('/remote_connect', type='http', auth='none', cors='*')
+ def remote_connect(self):
+ """
+ Establish a link with a customer box trough internet with a ssh tunnel
+ 1 - take a new auth_token on https://dashboard.ngrok.com/
+ 2 - copy past this auth_token on the IoT Box : http://IoT_Box:8069/remote_connect
+ 3 - check on ngrok the port and url to get access to the box
+ 4 - you can connect to the box with this command : ssh -p port -v pi@url
+ """
+ return remote_connect_template.render({
+ 'title': 'Remote debugging',
+ 'breadcrumb': 'Remote Debugging',
+ })
+
+ @http.route('/enable_ngrok', type='http', auth='none', cors='*', csrf=False)
+ def enable_ngrok(self, auth_token):
+ if subprocess.call(['pgrep', 'ngrok']) == 1:
+ subprocess.Popen(['ngrok', 'tcp', '-authtoken', auth_token, '-log', '/tmp/ngrok.log', '22'])
+ return 'starting with ' + auth_token
+ else:
+ return 'already running'
+
+ @http.route('/six_payment_terminal', type='http', auth='none', cors='*', csrf=False)
+ def six_payment_terminal(self):
+ return six_payment_terminal_template.render({
+ 'title': 'Six Payment Terminal',
+ 'breadcrumb': 'Six Payment Terminal',
+ 'terminalId': self.get_six_terminal(),
+ })
+
+ @http.route('/six_payment_terminal_add', type='http', auth='none', cors='*', csrf=False)
+ def add_six_payment_terminal(self, terminal_id):
+ helpers.write_file('odoo-six-payment-terminal.conf', terminal_id)
+ subprocess.check_call(["sudo", "service", "odoo", "restart"])
+ return 'http://' + helpers.get_ip() + ':8069'
+
+ @http.route('/six_payment_terminal_clear', type='http', auth='none', cors='*', csrf=False)
+ def clear_six_payment_terminal(self):
+ helpers.unlink_file('odoo-six-payment-terminal.conf')
+ subprocess.check_call(["sudo", "service", "odoo", "restart"])
+ return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069'>"
+
+ @http.route('/hw_proxy/upgrade', type='http', auth='none', )
+ def upgrade(self):
+ commit = subprocess.check_output(["git", "--work-tree=/home/pi/odoo/", "--git-dir=/home/pi/odoo/.git", "log", "-1"]).decode('utf-8').replace("\n", "<br/>")
+ flashToVersion = helpers.check_image()
+ actualVersion = helpers.get_version()
+ if flashToVersion:
+ flashToVersion = '%s.%s' % (flashToVersion.get('major', ''), flashToVersion.get('minor', ''))
+ return upgrade_page_template.render({
+ 'title': "Odoo's IoTBox - Software Upgrade",
+ 'breadcrumb': 'IoT Box Software Upgrade',
+ 'loading_message': 'Updating IoT box',
+ 'commit': commit,
+ 'flashToVersion': flashToVersion,
+ 'actualVersion': actualVersion,
+ })
+
+ @http.route('/hw_proxy/perform_upgrade', type='http', auth='none')
+ def perform_upgrade(self):
+ self.updating.acquire()
+ os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh')
+ self.updating.release()
+ return 'SUCCESS'
+
+ @http.route('/hw_proxy/get_version', type='http', auth='none')
+ def check_version(self):
+ return helpers.get_version()
+
+ @http.route('/hw_proxy/perform_flashing_create_partition', type='http', auth='none')
+ def perform_flashing_create_partition(self):
+ try:
+ response = subprocess.check_output(['sudo', 'bash', '-c', '. /home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/upgrade.sh; create_partition']).decode().split('\n')[-2]
+ if response in ['Error_Card_Size', 'Error_Upgrade_Already_Started']:
+ raise Exception(response)
+ return Response('success', status=200)
+ except subprocess.CalledProcessError as e:
+ raise Exception(e.output)
+ except Exception as e:
+ _logger.error('A error encountered : %s ' % e)
+ return Response(str(e), status=500)
+
+ @http.route('/hw_proxy/perform_flashing_download_raspios', type='http', auth='none')
+ def perform_flashing_download_raspios(self):
+ try:
+ response = subprocess.check_output(['sudo', 'bash', '-c', '. /home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/upgrade.sh; download_raspios']).decode().split('\n')[-2]
+ if response == 'Error_Raspios_Download':
+ raise Exception(response)
+ return Response('success', status=200)
+ except subprocess.CalledProcessError as e:
+ raise Exception(e.output)
+ except Exception as e:
+ self.clean_partition()
+ _logger.error('A error encountered : %s ' % e)
+ return Response(str(e), status=500)
+
+ @http.route('/hw_proxy/perform_flashing_copy_raspios', type='http', auth='none')
+ def perform_flashing_copy_raspios(self):
+ try:
+ response = subprocess.check_output(['sudo', 'bash', '-c', '. /home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/upgrade.sh; copy_raspios']).decode().split('\n')[-2]
+ if response == 'Error_Iotbox_Download':
+ raise Exception(response)
+ return Response('success', status=200)
+ except subprocess.CalledProcessError as e:
+ raise Exception(e.output)
+ except Exception as e:
+ self.clean_partition()
+ _logger.error('A error encountered : %s ' % e)
+ return Response(str(e), status=500)
diff --git a/addons/hw_posbox_homepage/views/configure_wizard.html b/addons/hw_posbox_homepage/views/configure_wizard.html
new file mode 100644
index 00000000..d492a500
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/configure_wizard.html
@@ -0,0 +1,180 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ $(document).ready(function () {
+ function changePage(key) {
+ $('.progressbar li[data-key=' + key + ']').prevAll().addClass('completed');
+ $('.progressbar li[data-key=' + key + ']').nextAll().removeClass('active completed');
+ $('.progressbar li[data-key=' + key + ']').addClass('active').removeClass('completed');
+ $('.config-steps.active').removeClass('active').addClass('o_hide');
+ $('.config-steps[data-key=' + key + ']').removeClass('o_hide').addClass('active');
+ }
+ $('.next-btn').on('click', function (ev) {
+ changePage($(ev.target).data('key'));
+ });
+ $('#config-form').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/step_configure',
+ type: 'post',
+ data: $('#config-form').serialize(),
+ }).done(function (url) {
+ $('.loading-block').addClass('o_hide');
+ changePage('done');
+ if(url) {
+ if ($('#iotname')[0].defaultValue == $('#iotname')[0].value){
+ var cpt = 30;
+ }else{
+ var cpt = 100;
+ }
+ setInterval(function(){
+ if(cpt === 0){
+ window.location = url
+ } else {
+ $('.redirect-message').html('You will be redirected to <a href="'+ url +'">' + url + '</a> in <b>' + cpt + '</b> seconds');
+ --cpt;
+ }
+ } , 1000);
+ }
+ }).fail(function () {
+ $('.error-message').text('Error in submitting data');
+ $('.loading-block').addClass('o_hide');
+ });
+ });
+ });
+ </script>
+ <style>
+ .config-steps .title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ }
+ .progressbar {
+ counter-reset: step;
+ z-index: 1;
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ padding: 0;
+ }
+ .progressbar li{
+ list-style-type: none;
+ float: left;
+ width: 33.33%;
+ position:relative;
+ text-align: center;
+ font-size: 0.8rem;
+ }
+ .progressbar li:before {
+ content:counter(step);
+ counter-increment: step;
+ height:30px;
+ width:30px;
+ line-height: 30px;
+ border: 2px solid #ddd;
+ display:block;
+ text-align: center;
+ margin: 0 auto 6px auto;
+ border-radius: 50%;
+ background-color: white;
+ color: #ddd;
+ font-size: 1rem;
+ }
+ .progressbar li:after {
+ content:'';
+ position: absolute;
+ width:100%;
+ height:2px;
+ background-color: #ddd;
+ top: 15px;
+ left: -50%;
+ z-index: -1;
+ }
+ .progressbar li:first-child:after {
+ content:none;
+ }
+ .progressbar li.active, .progressbar li.completed {
+ color:#875A7B;
+ }
+ .progressbar li:last-child:before {
+ content: '✔';
+ }
+ .progressbar li.active:before {
+ border-color:#875A7B;
+ background-color:#875A7B;
+ color: #fff;
+ }
+ .progressbar li.completed:before{
+ border-color:#875A7B;
+ background-color: #fff;
+ color: #875A7B;
+ }
+ .progressbar li.active + li:after{
+ background-color:#875A7B;
+ }
+ .footer-buttons {
+ display: inline-block;
+ width: 100%;
+ margin-top: 20px;
+ }
+ </style>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">Configure IoT Box</h2>
+ <ul class="progressbar">
+ <li class="active" data-key="server">Connect to Odoo</li>
+ <li data-key="wifi">Connect to Internet</li>
+ <li data-key="done">Done</li>
+ </ul>
+ <form id="config-form" style="margin-top: 20px;" action='/step_configure' method='POST'>
+ <div>
+ <div class="config-steps active" data-key="server">
+ <table align="center">
+ <tr>
+ <td>IoT Box Name</td>
+ <td><input type="text" id="iotname" name="iotname" value="{{ hostname }}"></td>
+ </tr>
+ <tr>
+ <td>Server token</td>
+ <td><input type="text" name="token" value="{{ server }}" placeholder="Paste your copied token here"></td>
+ </tr>
+ </table>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ Server token is not mandatory for the community version.
+ </div>
+ <div class="footer-buttons">
+ <a class="btn next-btn" style="float: right" data-key="wifi">Next</a>
+ </div>
+ </div>
+ <div class="config-steps wifi-step o_hide" data-key="wifi">
+ <table align="center">
+ <tr>
+ <td>Wifi Network</td>
+ <td>
+ <select name="essid">
+ {% for id in ssid -%}
+ <option value="{{ id }}">{{ id }}</option>
+ {%- endfor %}
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td><input type="password" name="password" placeholder="Optional"/></td>
+ </tr>
+ <input type="hidden" name="persistent" value="True"/>
+ </table>
+ <div class="footer-buttons">
+ <a class="btn next-btn" data-key="server">Previous</a>
+ <input class="btn" style="float: right" type="submit" value="Connect"/>
+ </div>
+ </div>
+ <div class="config-steps o_hide" data-key="done">
+ <h3 class="text-center" style="margin: 0;">✔ Nice! Your configuration is done.</h3>
+ <p class="text-center redirect-message" />
+ </div>
+ </div>
+ {{ loading_block_ui(loading_message) }}
+ </form>
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/handler_list.html b/addons/hw_posbox_homepage/views/handler_list.html
new file mode 100644
index 00000000..86e7487e
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/handler_list.html
@@ -0,0 +1,50 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ $(document).ready(function () {
+ $('#load_handler_btn').on('click', function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/load_iot_handlers',
+ }).done(function () {
+ $('.message-status').html('Handlers loaded successfully <br> Refreshing page');
+ setTimeout(function () {
+ location.reload(true);
+ }, 25000);
+ }).fail(function () {
+ setTimeout(function () {
+ location.reload(true);
+ }, 25000);
+ });
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center text-green">Interfaces list</h2>
+ <table align="center" width="50%" cellpadding="3">
+ {% for interfaces in interfaces_list -%}
+ <tr><td>{{ interfaces }}</td></tr>
+ {%- endfor %}
+ </table>
+ <h2 class="text-center text-green">Drivers list</h2>
+ <table align="center" width="50%" cellpadding="3">
+ {% for driver in drivers_list -%}
+ <tr><td>{{ driver }}</td></tr>
+ {%- endfor %}
+ </table>
+ {% if server %}
+ <div style="margin-top: 20px;" class="text-center">
+ <a id="load_handler_btn" class="btn" href='/load_iot_handlers'>Load handlers</a>
+ </div>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ You can clear the handlers configuration
+ <form style="display: inline-block;margin-left: 4px;" action='/handlers_clear'>
+ <input class="btn btn-sm" type="submit" value="Clear"/>
+ </form>
+ </div>
+ {% endif %}
+ {{ loading_block_ui('Loading Handlers') }}
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/homepage.html b/addons/hw_posbox_homepage/views/homepage.html
new file mode 100644
index 00000000..482c5451
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/homepage.html
@@ -0,0 +1,152 @@
+{% extends "layout.html" %}
+{% block head %}
+<style>
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ }
+ table tr {
+ border-bottom: 1px solid #f1f1f1;
+ }
+ table tr:last-child {
+ border-width: 0px;
+ }
+ table td {
+ padding: 8px;
+ border-left: 1px solid #f1f1f1;
+ }
+ table td:first-child {
+ border-left: 0;
+ }
+ td.heading {
+ font-weight: bold;
+ vertical-align: top;
+ width: 30%;
+ text-align: left;
+ }
+ .device-status {
+ margin: 6px 0;
+ }
+ .device-status .identifier {
+ font-size: 0.8rem;
+ max-width: 350px;
+ }
+ .device-status .indicator {
+ margin-left: 4px;
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ }
+ .device-status .device {
+ font-weight: 500;
+ }
+ .collapse .collapsible{
+ border: 1px solid #f1f1f1;
+ }
+ .collapse .title {
+ position: relative;
+ color: #00a09d;
+ cursor: pointer;
+ padding: 8px;
+ }
+ .collapse .active, .collapse .title:hover {
+ background-color: #f1f1f1;
+ color: #006d6b;
+ }
+ .collapse .content {
+ padding: 0 8px;
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.2s ease-out;
+ }
+ .arrow-down::after {
+ content: '\25bc';
+ padding: 0 10px;
+ position: absolute;
+ right: 0;
+ }
+ .arrow-up::after {
+ content: '\25b2';
+ padding: 0 10px;
+ position: absolute;
+ right: 0;
+ }
+</style>
+<script>
+ $(document).ready(function () {
+ $('.collapsible .title').on('click', function (ev) {
+ $(ev.target).toggleClass('active');
+ $(ev.target).toggleClass('arrow-down arrow-up');
+ var content = $(ev.target).next('.content');
+ var maxHeight = ( content.css('max-height') === '0px' ? content.prop('scrollHeight') : 0) + 'px';
+ content.css('max-height', maxHeight);
+ });
+ });
+</script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center text-green">Your IoT Box is up and running</h2>
+ <table align="center" cellpadding="3">
+ <tr>
+ <td class="heading">Name</td>
+ <td> {{ hostname }} <a class="btn btn-sm float-right" href='/server'>configure</a></td>
+ </tr>
+ <tr>
+ <td class="heading">Version</td>
+ <td> {{ version }} <a class="btn btn-sm float-right" href='/hw_proxy/upgrade/'>update</a></td>
+ </tr>
+ <tr>
+ <td class="heading">IP Address</td>
+ <td>{{ ip }}</a></td>
+ </tr>
+ <tr>
+ <td class="heading">Mac Address</td>
+ <td> {{ mac }}</td>
+ </tr>
+ <tr>
+ <td class="heading">Network</td>
+ <td>{{ network_status }} <a class="btn btn-sm float-right" href='/wifi'>configure wifi</a></td>
+ </tr>
+ <tr>
+ <td class="heading">Server</td>
+ <td><a href='{{ server_status }}' target=_blank>{{ server_status }}<a class="btn btn-sm float-right" href='/server'>configure</a></td>
+ </tr>
+ {% if server_status != "Not Configured" %}
+ <tr>
+ <td class="heading">Six payment terminal</td>
+ <td>{{ six_terminal }} <a class="btn btn-sm float-right" href='/six_payment_terminal'>configure</a></td>
+ </tr>
+ {% endif %}
+ <tr>
+ <td class="heading">IOT Device</td>
+ <td>
+ <div class="collapse">
+ {% if iot_device_status|length == 0 %}
+ No Device Found
+ {% endif %}
+ {% for iot_devices in iot_device_status|groupby('type') %}
+ <div class="collapsible">
+ <div class="title arrow-down">{{ iot_devices.grouper|capitalize }}s</div>
+ <div class="content">
+ {% for device in iot_devices.list %}
+ <div class="device-status">
+ <span class="device">{{ device['name'] }}</span>
+ <div class="identifier">{{ device['identifier'] }}</div>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ <br><center><a class="btn btn-sm" href='/list_handlers'>handlers list</a></center>
+ </td>
+ </tr>
+ </table>
+ <div style="margin: 20px auto 10px auto;" class="text-center">
+ <a class="btn" href='/point_of_sale/display'>POS Display</a>
+ <a class="btn" style="margin-left: 10px;" href='/remote_connect'>Remote Debug</a>
+ <a target="_blank" class="btn" style="margin-left: 10px;" href="http://{{ ip }}:631">Printers server</a>
+ {% if server_status != "Not Configured" %}
+ <a class="btn" style="margin-left: 10px;" href='/list_credential'>Credential</a>
+ {% endif %}
+ </div>
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/layout.html b/addons/hw_posbox_homepage/views/layout.html
new file mode 100644
index 00000000..5d0d7c6e
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/layout.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="cache-control" content="no-cache" />
+ <meta http-equiv="pragma" content="no-cache" />
+ <title>{{ title or "Odoo's IoT Box" }}</title>
+ <script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
+ <style>
+ body {
+ width: 600px;
+ margin: 30px auto;
+ font-family: sans-serif;
+ text-align: justify;
+ color: #6B6B6B;
+ background-color: #f1f1f1;
+ }
+ .text-green {
+ color: #28a745;
+ }
+ .text-red {
+ color: #dc3545;
+ }
+ .text-blue {
+ color: #007bff;
+ }
+ .text-center {
+ text-align: center;
+ }
+ .float-right {
+ float: right;
+ }
+ .btn {
+ display: inline-block;
+ padding: 8px 15px;
+ border: 1px solid #dadada;
+ border-radius: 3px;
+ font-weight: bold;
+ font-size: 0.8rem;
+ background: #fff;
+ color: #00a09d;
+ cursor: pointer;
+ }
+ .btn-sm {
+ padding: 4px 8px;
+ font-size: 1.0rem;
+ font-weight: normal;
+ }
+ .btn:hover {
+ background-color: #f1f1f1;
+ }
+ a {
+ text-decoration: none;
+ color: #00a09d;
+ }
+ a:hover {
+ color: #006d6b;
+ }
+ .container {
+ padding: 10px 20px;
+ background: #ffffff;
+ border-radius: 8px;
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.17);
+ }
+ .breadcrumb {
+ margin-bottom: 10px;
+ font-size: 0.9rem;
+ }
+ input[type="text"], input[type="password"] {
+ padding: 6px 12px;
+ font-size: 1rem;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ color: inherit;
+ }
+ input::placeholder {
+ color: #ccc;
+ opacity: 1; /* Firefox */
+ }
+ select {
+ padding: 6px 12px;
+ font-size: 1rem;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ color: inherit;
+ background: #ffffff;
+ width: 100%;
+ }
+ .o_hide {
+ display: none;
+ }
+ .font-small {
+ font-size: 0.8rem;
+ }
+ .footer {
+ margin-top: 12px;
+ text-align: right;
+ }
+ .footer a {
+ margin-left: 8px;
+ }
+ .loading-block {
+ position: absolute;
+ background-color: #0a060661;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 9999;
+ }
+ .loading-message-block {
+ text-align: center;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ }
+ .loading-message {
+ font-size: 14px;
+ line-height: 20px;
+ color:white
+ }
+ @keyframes spin {
+ from {transform:rotate(0deg);}
+ to {transform:rotate(360deg);}
+ }
+ </style>
+ {% block head %}{% endblock %}
+ </head>
+ <body>
+ {%if breadcrumb %}
+ <div class="breadcrumb"><a href="/">Home</a> / <span>{{ breadcrumb }}</span></div>
+ {% endif %}
+ <div class="container">
+ {% block content %}{% endblock %}
+ <p class="error-message text-red" style="text-align: right;" />
+ </div>
+ <div class="footer">
+ <a href='https://www.odoo.com/help'>Help</a>
+ <a href='https://www.odoo.com/documentation/14.0/applications/productivity/iot.html'>Documentation</a>
+ </div>
+ </body>
+</html>
diff --git a/addons/hw_posbox_homepage/views/list_credential.html b/addons/hw_posbox_homepage/views/list_credential.html
new file mode 100644
index 00000000..87a8f09f
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/list_credential.html
@@ -0,0 +1,68 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ var _onQueryDone = function () {
+ $('.message-status').html('Updated configuration <br> Refreshing page');
+ setTimeout(function () {
+ location.reload();
+ }, 30000);
+ }
+ $(document).ready(function () {
+ $('#list-credential').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/save_credential',
+ type: 'post',
+ data: $('#list-credential').serialize(),
+ }).always(_onQueryDone);
+ });
+ $('#credential-clear').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/clear_credential',
+ type: 'get',
+ }).always(_onQueryDone);
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">List Credential</h2>
+ <p>
+ Set the DB UUID and your Contract Number you want to use.
+ </p>
+ <form id="list-credential" action='/save_credential' method='POST'>
+ <table align="center">
+ <tr>
+ <td>DB uuid</td>
+ <td><input type="text" name="db_uuid" value="{{ db_uuid }}"></td>
+ </tr>
+ <tr>
+ <td>Contract Number</td>
+ <td><input type="text" name="enterprise_code" value="{{ enterprise_code }}"></td>
+ </tr>
+ <tr>
+ <td/>
+ <td><input class="btn" type="submit" value="Save"/></td>
+ </tr>
+ </table>
+ {{ loading_block_ui(loading_message) }}
+ </form>
+ {% if db_uuid or enterprise_code %}
+ <p class="text-center font-small">
+ Current DB uuid: <strong>{{ db_uuid }}</strong>
+ </p>
+ <p class="text-center font-small">
+ Current Contract Number: <strong>{{ enterprise_code }}</strong>
+ </p>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ You can clear the credential configuration
+ <form id="credential-clear" style="display: inline-block;margin-left: 4px;">
+ <input class="btn btn-sm" type="submit" value="Clear"/>
+ </form>
+ </div>
+ {% endif %}
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/loading.html b/addons/hw_posbox_homepage/views/loading.html
new file mode 100644
index 00000000..a4c040fc
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/loading.html
@@ -0,0 +1,14 @@
+{% macro loading_block_ui(message) %}
+<div class="loading-block o_hide">
+ <div class="loading-message-block">
+ <div style="height: 50px">
+ <img src="/web/static/src/img/spin.png" style="animation: spin 4s infinite linear;" alt="Loading...">
+ </div>
+ <br>
+ <div class="loading-message">
+ <span class="message-title">Please wait..</span><br>
+ <span class="message-status">{{ message }}</span>
+ </div>
+ </div>
+</div>
+{% endmacro %}
diff --git a/addons/hw_posbox_homepage/views/remote_connect.html b/addons/hw_posbox_homepage/views/remote_connect.html
new file mode 100644
index 00000000..ab9628ec
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/remote_connect.html
@@ -0,0 +1,42 @@
+{% extends "layout.html" %}
+{% block head %}
+ <script>
+ $(function () {
+ var upgrading = false;
+ $('#enable_debug').click(function () {
+ var auth_token = $('#auth_token').val();
+ if (auth_token == "") {
+ alert('Please provide an authentication token.');
+ } else {
+ $.ajax({
+ url: '/enable_ngrok',
+ data: {
+ 'auth_token': auth_token
+ }
+ }).always(function (response) {
+ if (response === 'already running') {
+ alert('Remote debugging already activated.');
+ } else {
+ $('#auth_token').attr('disabled','disabled');
+ $('#enable_debug').html('Enabled remote debugging');
+ $('#enable_debug').removeAttr('href', '')
+ $('#enable_debug').off('click');
+ }
+ });
+ }
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">Remote Debugging</h2>
+ <p class='text-red'>
+ This allows someone who give a ngrok authtoken to gain remote access to your IoT Box, and
+ thus your entire local network. Only enable this for someone
+ you trust.
+ </p>
+ <div class='text-center'>
+ <input type="text" id="auth_token" size="42" placeholder="Authentication Token"/> <br/>
+ <a class="btn" style="margin: 18px auto;" id="enable_debug" href="#">Enable Remote Debugging</a>
+ </div>
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/server_config.html b/addons/hw_posbox_homepage/views/server_config.html
new file mode 100644
index 00000000..6824ee67
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/server_config.html
@@ -0,0 +1,60 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ $(document).ready(function () {
+ $('#server-config').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/server_connect',
+ type: 'post',
+ data: $('#server-config').serialize(),
+ }).fail(function () {
+ $('.message-status').html('Configure Domain Server <br> Redirect to IoT Box');
+ if ($('#iotname')[0].defaultValue == $('#iotname')[0].value){
+ var rebootTime = 30000;
+ }else{
+ var rebootTime = 100000;
+ }
+ setTimeout(function () {
+ location.reload(true);
+ }, rebootTime);
+ });
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">Configure Odoo Server</h2>
+ <p>
+ Paste the token from the Connect wizard in your Odoo instance in the Server Token field. If you change the IoT Box Name,
+ your IoT Box will need a reboot.
+ </p>
+ <form id="server-config" action='/server_connect' method='POST'>
+ <table align="center">
+ <tr>
+ <td>IoT Box Name</td>
+ <td><input type="text" id="iotname" name="iotname" value="{{ hostname }}"></td>
+ </tr>
+ <tr>
+ <td>Server Token</td>
+ <td><input type="text" name="token"></td>
+ </tr>
+ <tr>
+ <td/>
+ <td><input class="btn" type="submit" value="Connect"/></td>
+ </tr>
+ </table>
+ <p class="text-center font-small">
+ Your current server <strong>{{ server_status }}</strong>
+ </p>
+ {{ loading_block_ui(loading_message) }}
+ </form>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ You can clear the server configuration
+ <form style="display: inline-block;margin-left: 4px;" action='/server_clear'>
+ <input class="btn btn-sm" type="submit" value="Clear"/>
+ </form>
+ </div>
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/six_payment_terminal.html b/addons/hw_posbox_homepage/views/six_payment_terminal.html
new file mode 100644
index 00000000..622c6a84
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/six_payment_terminal.html
@@ -0,0 +1,61 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ var _onQueryDone = function () {
+ $('.message-status').html('Updated configuration <br> Refreshing page');
+ setTimeout(function () {
+ location.reload();
+ }, 30000);
+ }
+ $(document).ready(function () {
+ $('#terminal-id').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/six_payment_terminal_add',
+ type: 'post',
+ data: $('#terminal-id').serialize(),
+ }).always(_onQueryDone);
+ });
+ $('#terminal-clear').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/six_payment_terminal_clear',
+ type: 'get',
+ }).always(_onQueryDone);
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">Six Payment Terminal</h2>
+ <p>
+ Set the Terminal ID (TID) of the terminal you want to use.
+ </p>
+ <form id="terminal-id" action='/six_payment_terminal_add' method='POST'>
+ <table align="center">
+ <tr>
+ <td>Terminal ID</td>
+ <td><input type="text" name="terminal_id"></td>
+ </tr>
+ <tr>
+ <td/>
+ <td><input class="btn" type="submit" value="Connect"/></td>
+ </tr>
+ </table>
+ {{ loading_block_ui(loading_message) }}
+ </form>
+ {% if terminalId %}
+ <p class="text-center font-small">
+ Current Terminal Id: <strong>{{ terminalId }}</strong>
+ </p>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ You can clear the terminal configuration
+ <form id="terminal-clear" style="display: inline-block;margin-left: 4px;">
+ <input class="btn btn-sm" type="submit" value="Clear"/>
+ </form>
+ </div>
+ {% endif %}
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/upgrade_page.html b/addons/hw_posbox_homepage/views/upgrade_page.html
new file mode 100644
index 00000000..81fe2c3b
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/upgrade_page.html
@@ -0,0 +1,95 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
+ <script>
+ $(function() {
+ var updating = false;
+ $('#upgrade').click(function() {
+ if (!updating) {
+ updating = true;
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url:'/hw_proxy/perform_upgrade/'
+ }).done(function() {
+ $('.message-title').text('Upgrade successful');
+ var cpt = 25;
+ setInterval(function() {
+ --cpt;
+ if (cpt === 0) {location.reload();}
+ $('.message-status').text('Restarting the IoTBox. Available in ' + cpt);
+ } , 1000);
+ }).fail(function() {
+ $('.error-message').text('Upgrade Failed');
+ });
+ }
+ });
+ $('#flash').click(async function() {
+ if (confirm('Are you sure you want to flash your IoT Box?\nThe box will be unavailable for ~30 min\nDo not turn off the box or close this page during the flash.\nThis page will reaload when your box is ready.')) {
+ $('.loading-block').removeClass('o_hide');
+ $('.message-title').text('IoTBox perform a self flashing it take a lot of time (~30min).');
+ $('.message-status').text('Prepare space for IoTBox.');
+ try {
+ await $.ajax({url: '/hw_proxy/perform_flashing_create_partition/'}).promise();
+ $('.message-status').text('Prepare new boot partition.');
+ await $.ajax({url: '/hw_proxy/perform_flashing_download_raspios/'}).promise();
+ $('.message-status').text('Download file for new boot partition.');
+ await $.ajax({url: '/hw_proxy/perform_flashing_copy_raspios/'}).promise();
+ $('.message-status').text('Prepare to restart and installation of the new version of the IoT Box.');
+ setTimeout(function() {
+ $('.message-status').text('The auto flash is almost finished - the page will be automatically reloaded');
+ setInterval(function() {
+ $.ajax({
+ url: '/hw_proxy/get_version',
+ timeout: 4000,
+ }).done(function(version) {
+ if (version == {{ flashToVersion }}) {
+ window.location = '/';
+ }
+ });
+ } , 2000);
+ }, 240000);
+ }
+ catch(error) {
+ $('.loading-block').addClass('o_hide');
+ $('.error-message').text(error.responseText);
+ }
+ }
+ });
+ });
+ </script>
+ <style>
+ .commit-details {
+ background: #f1f1f1;
+ padding: 10px 10px 0 10px;
+ border-radius: 5px;
+ }
+ </style>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">IoT Box Software Upgrade</h2>
+ <p>
+ This tool will help you perform an upgrade of the IoTBox's software over the internet.
+ However the preferred method to upgrade the IoTBox is to flash the sd-card with
+ the <a href='https://nightly.odoo.com/master/iotbox/iotbox-latest.zip'>latest image</a>. The upgrade
+ procedure is explained into to the
+ <a href='https://www.odoo.com/documentation/14.0/applications/productivity/iot.html'>IoTBox manual</a>
+ </p>
+ <p>
+ To upgrade the IoTBox, click on the upgrade button. The upgrade will take a few minutes. <b>Do not reboot</b> the IoTBox during the upgrade.
+ </p>
+ <div class="commit-details">
+ <div style="padding-bottom: 5px; font-weight: bold;">
+ Latest patch:
+ </div>
+ <pre style="margin: 0;padding: 15px 0; overflow: auto;">{{ commit|safe }}</pre>
+ </div>
+ <div class="text-center" style="margin: 15px auto;">
+ {% if flashToVersion %}
+ <a class="btn" href='#' id='flash'>Upgrade to {{ flashToVersion }}</a>
+ {% else %}
+ <a class="btn" href='#' id='upgrade'>Upgrade</a>
+ {% endif %}
+ </div>
+ {{ loading_block_ui(loading_message) }}
+{% endblock %}
diff --git a/addons/hw_posbox_homepage/views/wifi_config.html b/addons/hw_posbox_homepage/views/wifi_config.html
new file mode 100644
index 00000000..94e0579b
--- /dev/null
+++ b/addons/hw_posbox_homepage/views/wifi_config.html
@@ -0,0 +1,71 @@
+{% extends "layout.html" %}
+{% from "loading.html" import loading_block_ui %}
+{% block head %}
+ <script>
+ $(document).ready(function () {
+ $('#wifi-config').submit(function(e){
+ e.preventDefault();
+ $('.loading-block').removeClass('o_hide');
+ $.ajax({
+ url: '/wifi_connect',
+ type: 'post',
+ data: $('#wifi-config').serialize(),
+ }).done(function (message) {
+ var data = JSON.parse(message);
+ var message = data.message;
+ if (data.server) {
+ message += '<br>'+ data.server.message;
+ setTimeout(function () {
+ window.location = data.server.url;
+ }, 30000);
+ }
+ $('.message-status').html(message);
+ }).fail(function () {
+ $('.error-message').text('Error in connecting to wifi');
+ $('.loading-block').addClass('o_hide');
+ });
+ });
+ });
+ </script>
+{% endblock %}
+{% block content %}
+ <h2 class="text-center">Configure Wifi</h2>
+ <p>
+ Here you can configure how the iotbox should connect to wireless networks.
+ Currently only Open and WPA networks are supported. When enabling the persistent checkbox,
+ the chosen network will be saved and the iotbox will attempt to connect to it every time it boots.
+ </p>
+ <form id="wifi-config" action='/wifi_connect' method='POST'>
+ <table align="center">
+ <tr>
+ <td>ESSID</td>
+ <td>
+ <select name="essid">
+ {% for id in ssid -%}
+ <option value="{{ id }}">{{ id }}</option>
+ {%- endfor %}
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td><input type="password" name="password" placeholder="optional"/></td>
+ </tr>
+ <tr>
+ <td>Persistent</td>
+ <td><input type="checkbox" name="persistent"/></td>
+ </tr>
+ <tr>
+ <td/>
+ <td><input class="btn" type="submit" value="Connect"/></td>
+ </tr>
+ </table>
+ </form>
+ <div class="text-center font-small" style="margin: 10px auto;">
+ You can clear the persistent configuration
+ <form style="display: inline-block;margin-left: 4px;" action='/wifi_clear'>
+ <input class="btn btn-sm" type="submit" value="Clear"/>
+ </form>
+ </div>
+ {{ loading_block_ui(loading_message) }}
+{% endblock %}