mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] abstract communication with shuttle
This commit is contained in:
committed by
Hai Lang
parent
084c86b356
commit
06fa3da67f
@@ -71,7 +71,12 @@ class StockLocation(models.Model):
|
||||
location.vertical_lift_shuttle_id = shuttle
|
||||
|
||||
def _hardware_vertical_lift_tray(self, cell_location=None):
|
||||
"""Send instructions to the vertical lift hardware
|
||||
payload = self._hardware_vertical_lift_tray_payload(cell_location)
|
||||
res = self.vertical_lift_shuttle_id._hardware_send_message(payload)
|
||||
return res
|
||||
|
||||
def _hardware_vertical_lift_tray_payload(self, cell_location=None):
|
||||
"""Prepare the message to be sent to the vertical lift hardware
|
||||
|
||||
Private method, this is where the implementation actually happens.
|
||||
Addons can add their instructions based on the hardware used for
|
||||
@@ -120,9 +125,9 @@ class StockLocation(models.Model):
|
||||
from_left,
|
||||
from_bottom,
|
||||
)
|
||||
self.env.user.notify_info(
|
||||
message=message, title=_("Lift Simulation")
|
||||
)
|
||||
return message
|
||||
else:
|
||||
return super()._hardware_vertical_lift_tray_payload(cell_location)
|
||||
|
||||
def fetch_vertical_lift_tray(self, cell_location=None):
|
||||
"""Send instructions to the vertical lift hardware
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
# Copyright 2019 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
import socket
|
||||
import ssl
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VerticalLiftShuttle(models.Model):
|
||||
_name = "vertical.lift.shuttle"
|
||||
@@ -26,6 +31,13 @@ class VerticalLiftShuttle(models.Model):
|
||||
hardware = fields.Selection(
|
||||
selection="_selection_hardware", default="simulation", required=True
|
||||
)
|
||||
server = fields.Char(help="hostname or IP address of the server")
|
||||
port = fields.Integer(
|
||||
help="network port of the server on which to send the message"
|
||||
)
|
||||
use_tls = fields.Boolean(
|
||||
help="set this if the server expects TLS wrapped communication"
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
@@ -64,6 +76,85 @@ class VerticalLiftShuttle(models.Model):
|
||||
),
|
||||
}
|
||||
|
||||
def _hardware_send_message(self, payload):
|
||||
"""default implementation for message sending
|
||||
|
||||
If in hardware is 'simulation' then display a simple message.
|
||||
Otherwise defaults to connecting to server:port using a TCP socket
|
||||
(optionnally wrapped with TLS) and sending the payload, then waiting
|
||||
for a response and disconnecting.
|
||||
|
||||
:param payload: a bytes object containing the payload
|
||||
|
||||
"""
|
||||
self.ensure_one()
|
||||
_logger.info('send %r', payload)
|
||||
if self.hardware == "simulation":
|
||||
self.env.user.notify_info(message=payload,
|
||||
title=_("Lift Simulation"))
|
||||
return True
|
||||
else:
|
||||
conn = self._hardware_get_server_connection()
|
||||
try:
|
||||
offset = 0
|
||||
while True:
|
||||
size = conn.send(payload[offset:])
|
||||
offset += size
|
||||
if offset >= len(payload) or not size:
|
||||
break
|
||||
response = self._hardware_recv_response(conn)
|
||||
_logger.info('recv %r', response)
|
||||
return self._check_server_response(payload, response)
|
||||
finally:
|
||||
self._hardware_release_server_connection(conn)
|
||||
|
||||
def _hardware_recv_response(self, conn):
|
||||
"""Default implementation expects the remote server to close()
|
||||
the socket after sending the reponse.
|
||||
Override to match the protocol implemented by the hardware.
|
||||
|
||||
:param conn: a socket connected to the server
|
||||
:return: the response sent by the server, as a bytes object
|
||||
"""
|
||||
response = b''
|
||||
chunk = True
|
||||
while chunk:
|
||||
chunk = conn.recv(1024)
|
||||
response += chunk
|
||||
return response
|
||||
|
||||
def _check_server_response(self, payload, response):
|
||||
"""Use this to check if the response is a success or a failure
|
||||
|
||||
:param payload: the payload sent
|
||||
:param response: the response received
|
||||
:return: True if the response is a succes, False otherwise
|
||||
"""
|
||||
return True
|
||||
|
||||
def _hardware_release_server_connection(self, conn):
|
||||
conn.close()
|
||||
|
||||
def _hardware_get_server_connection(self):
|
||||
"""This implementation will yield a new connection to the server
|
||||
and close() it when exiting the context.
|
||||
Override to match the communication protocol of your hardware"""
|
||||
conn = socket.create_connection((self.server, self.port))
|
||||
if self.use_tls:
|
||||
ctx = ssl.create_default_context()
|
||||
self._hardware_update_tls_context(ctx)
|
||||
conntls = ctx.wrap_socket(conn, server_hostname=self.server)
|
||||
return conntls
|
||||
else:
|
||||
return conn
|
||||
|
||||
def _hardware_update_tls_context(self, context):
|
||||
"""Update the TLS context, e.g. to add a client certificate.
|
||||
|
||||
This method does nothing, override to match your communication
|
||||
protocol."""
|
||||
pass
|
||||
|
||||
def _operation_for_mode(self):
|
||||
model = self._model_for_mode[self.mode]
|
||||
record = self.env[model].search([("shuttle_id", "=", self.id)])
|
||||
|
||||
@@ -58,12 +58,19 @@
|
||||
<field name="model">vertical.lift.shuttle</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Operations">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="mode"/>
|
||||
<field name="location_id"/>
|
||||
<field name="hardware"/>
|
||||
</group>
|
||||
<group name="main">
|
||||
<group name="left">
|
||||
<field name="name"/>
|
||||
<field name="mode"/>
|
||||
<field name="location_id"/>
|
||||
<field name="hardware"/>
|
||||
</group>
|
||||
<group string="Network" name="network">
|
||||
<field name="server"/>
|
||||
<field name="port"/>
|
||||
<field name="use_tls"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user