Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
PosAgentPro
https://github.com/dieg0-a/posagentpro-src
Admin
PosAgentPro is a point-of-sale agent system that leverages AI to automate and enhance retail
...
Tokens:
482,700
Snippets:
3,401
Trust Score:
4.5
Update:
3 months ago
Context
Skills
Chat
Benchmark
57.8
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# POS Agent Pro POS Agent Pro is a cross-platform Point of Sale (POS) hardware proxy application built with C++20 and Qt6. It acts as a bridge between web-based POS systems (like Odoo) and thermal receipt printers, enabling browser-based applications to print receipts and control cash drawers through a local HTTP proxy server. The application supports multiple printer connection types including Windows spooler, Linux USB RAW devices, and TCP/IP network printers. The core functionality centers around an embedded HTTP server (using uWebSockets) that exposes a JSON-RPC API compatible with Odoo's POS hardware proxy protocol. When a POS system sends a print request containing a base64-encoded JPEG receipt image, the application decodes the image, converts it to ESC/POS printer commands using dithering algorithms for optimal thermal print quality, and sends the raw data to the configured printer. The Qt-based GUI provides a system tray interface for printer configuration, status monitoring, and receipt preview. ## HTTP API Endpoints ### Hello Endpoint - Connection Health Check The `/hw_proxy/hello` endpoint provides a simple ping mechanism to verify the proxy server is running and accessible. POS systems use this to detect if local hardware proxy is available. ```bash # Check if POS Agent is running curl -X GET http://localhost:8069/hw_proxy/hello # Response: # ping ``` ### Handshake Endpoint - Initialize Session The `/hw_proxy/handshake` endpoint establishes a session with the hardware proxy. It accepts a JSON-RPC request and returns a success confirmation with the same request ID. ```bash # Initialize handshake with POS system curl -X POST http://localhost:8069/hw_proxy/handshake \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 1, "method": "handshake", "params": {}}' # Response: # {"jsonrpc": "2.0", "id": 1, "result": true} ``` ### Status Endpoint - Get Hardware Status The `/hw_proxy/status_json` endpoint returns the current connection status of all supported hardware devices including printers and scanners. ```bash # Query printer and scanner status curl -X POST http://localhost:8069/hw_proxy/status_json \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 2, "method": "status_json", "params": {}}' # Response when printer is connected: # {"jsonrpc": "2.0", "id": 2, "result": {"printer": {"status": "connected", "messages": ""}, "scanner": {"status": "disconnected", "messages": ""}}} # Response when printer is disconnected: # {"jsonrpc": "2.0", "id": 2, "result": {"printer": {"status": "disconnected", "messages": ""}, "scanner": {"status": "disconnected", "messages": ""}}} ``` ### Default Printer Action - Print Receipt or Open Cash Drawer The `/hw_proxy/default_printer_action` endpoint handles print jobs and cash drawer commands. For printing, it accepts a base64-encoded JPEG image of the receipt. For cash drawer operations, it sends the appropriate ESC/POS command sequence. ```bash # Print a receipt (base64-encoded JPEG image) curl -X POST http://localhost:8069/hw_proxy/default_printer_action \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "default_printer_action", "params": { "data": { "action": "print_receipt", "receipt": "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRof..." } } }' # Response: # {"jsonrpc": "2.0", "id": 3, "result": true} # Open cash drawer curl -X POST http://localhost:8069/hw_proxy/default_printer_action \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "default_printer_action", "params": { "data": { "action": "cashbox" } } }' # Response: # {"jsonrpc": "2.0", "id": 4, "result": true} ``` ## Core Classes and Functions ### GlobalState - Application State Management The `GlobalState` class manages the application's global state including printer configuration, print job queue, network thread, and settings persistence. It provides static methods for accessing and modifying application state in a thread-safe manner. ```cpp #include "messagesystem.h" // Register a printer driver PrinterLinuxUSBRAW* usbPrinter = new PrinterLinuxUSBRAW(); GlobalState::registerPrinter("Linux USB Printer", usbPrinter); // Set the current active printer GlobalState::setCurrentPrinter("Linux USB Printer"); // Configure printer settings GlobalState::printerSetString("device", "/dev/usb/lp0"); GlobalState::printerSetInt("gamma", 240); GlobalState::printerSetInt("max_width", 576); // Check printer status GlobalState::updatePrinterStatus(); device_status status = GlobalState::getPrinterStatus(); if (status == CONNECTED) { std::cout << "Printer ready" << std::endl; } // Enqueue a print job (JPEG data as std::string) std::string jpeg_data = base64::Decode(base64_receipt_string); GlobalState::enqueuePrintJob(std::move(jpeg_data), JPEG); // Open cash drawer GlobalState::enqueuePrintJob("dummy", CASHDRAWER); // Process queued print jobs GlobalState::processQueue(); // Start/stop the HTTP server GlobalState::setHttpPort(8069); GlobalState::startNetworkThread(); // ... later ... GlobalState::stopNetworkThread(); ``` ### escpos - ESC/POS Command Generator The `escpos` class generates ESC/POS printer command sequences for thermal printers. It provides a fluent interface for building print commands including image rendering with Bayer dithering, paper feed, paper cut, and cash drawer control. ```cpp #include "escpos.hpp" #include "jpeg.hpp" // Basic ESC/POS command sequence for printing an image escpos generator; std::string commands = generator .begin() // Reset buffer .image_from_jpeg(jpeg_data, 576, 240) // Render JPEG (max_width=576, gamma=240) .feednlines(3) // Feed 3 lines after image .fullcut() // Cut paper .end(); // Get command string // Send commands to printer printer->send_raw(commands); // Open cash drawer only escpos drawer_cmd; std::string cash_drawer_commands = drawer_cmd .begin() .cashdrawer() // ESC p command for cash drawer .end(); // Using jpeg object directly for better performance jpeg receipt_image; if (receipt_image.decode(jpeg_binary_data)) { escpos img_gen; std::string img_commands = img_gen .begin() .image_from_jpeg(receipt_image, 576, 240) .feednlines(5) .fullcut() .end(); } ``` ### jpeg - JPEG Image Decoder The `jpeg` class wraps libjpeg-turbo to decode JPEG images from binary data. It provides access to raw pixel data, dimensions, and color components needed for ESC/POS image conversion. ```cpp #include "jpeg.hpp" #include <iostream> // Decode a JPEG from binary string data std::string jpeg_binary_data = /* binary JPEG data */; jpeg image; if (image.decode(jpeg_binary_data)) { std::cout << "Image decoded successfully" << std::endl; std::cout << "Width: " << image.width() << std::endl; std::cout << "Height: " << image.height() << std::endl; std::cout << "Components: " << image.components() << std::endl; // 1=grayscale, 3=RGB // Access raw pixel data (row pointers) const unsigned char* const* pixels = image.image_memory_ptr(); // Example: Access pixel at row 0, column 0 int bytesPerPixel = image.components(); unsigned char r = pixels[0][0 * bytesPerPixel]; unsigned char g = pixels[0][0 * bytesPerPixel + 1]; unsigned char b = pixels[0][0 * bytesPerPixel + 2]; } else { std::cerr << "Failed to decode JPEG" << std::endl; } // Check if memory is allocated if (image.isAllocated()) { // Safe to use image data } ``` ### base64 - Base64 Encoding/Decoding The `base64` namespace provides functions for encoding and decoding base64 strings, essential for handling receipt images transmitted as base64-encoded data in JSON-RPC requests. ```cpp #include "base64.hpp" #include <iostream> // Decode base64 receipt data from POS system std::string base64_receipt = "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQ..."; std::string jpeg_binary = base64::Decode(base64_receipt); // Now jpeg_binary contains raw JPEG bytes ready for decoding jpeg image; image.decode(jpeg_binary); // Encode binary data to base64 (for logging or transmission) std::string original_data = "Hello, World!"; std::string encoded = base64::Encode(original_data); std::cout << "Encoded: " << encoded << std::endl; // SGVsbG8sIFdvcmxkIQ== // Round-trip verification std::string decoded = base64::Decode(encoded); assert(decoded == original_data); ``` ### Printer Classes - Printer Interface Hierarchy The printer class hierarchy provides abstraction for different printer connection types. `Printer` is the base class, `PrinterRaw` adds ESC/POS support, and concrete implementations handle specific connection methods. ```cpp #include "printer.hpp" #include "messagesystem.h" // Linux USB RAW Printer #ifdef __linux__ PrinterLinuxUSBRAW usb_printer; usb_printer.setString("device", "/dev/usb/lp0"); usb_printer.setInt("gamma", 240); usb_printer.setInt("max_width", 576); usb_printer.setInt("lines_to_feed", 3); // Check connection status device_status status = usb_printer.updateAndGetStatus(); if (status == CONNECTED) { // Print a JPEG receipt std::string jpeg_data = /* JPEG binary data */; usb_printer.printJPEG(jpeg_data); // Or with a jpeg object jpeg receipt; receipt.decode(jpeg_data); usb_printer.printJPEG(receipt); // Open cash drawer usb_printer.openCashDrawer(); } // Linux TCP/IP Network Printer PrinterThermalLinuxTCPIP network_printer; network_printer.setString("address", "192.168.1.100"); network_printer.setString("port", "9100"); network_printer.setInt("gamma", 240); if (network_printer.connectToPrinter()) { network_printer.printJPEG(jpeg_data); } #endif // Access printer configuration fields std::map<std::string, input_field*> const& fields = usb_printer.getFieldsByName(); for (const auto& [name, field] : fields) { std::cout << name << ": " << field->get_string() << std::endl; } // Get printer settings int pixel_width = dynamic_cast<PrinterRaw*>(&usb_printer)->getPixelWidth(); int gamma_value = dynamic_cast<PrinterRaw*>(&usb_printer)->getGamma(); std::string protocol = dynamic_cast<PrinterRaw*>(&usb_printer)->getPrintStandard(); ``` ### JSON Request Processing The `json` namespace contains functions for processing JSON-RPC requests from POS systems. These functions parse incoming requests, extract parameters, and generate appropriate JSON-RPC responses. ```cpp #include "json.hpp" #include <iostream> // Process a status request const char* status_request = R"({ "jsonrpc": "2.0", "id": 42, "method": "status_json", "params": {} })"; std::string status_response = json::getJsonStatusString(status_request); // Returns: {"jsonrpc": "2.0", "id": 42, "result": {"printer": {"status": "connected", "messages": ""}, "scanner": {"status": "disconnected", "messages": ""}}} // Process a handshake request const char* handshake_request = R"({ "jsonrpc": "2.0", "id": 1, "method": "handshake", "params": {} })"; std::string handshake_response = json::getResultTrueString(handshake_request); // Returns: {"jsonrpc": "2.0", "id": 1, "result": true} // Process a print action request const char* print_request = R"({ "jsonrpc": "2.0", "id": 5, "method": "default_printer_action", "params": { "data": { "action": "print_receipt", "receipt": "/9j/4AAQSkZJRg..." } } })"; std::string print_response = json::PrinterDefaultAction(print_request); // Enqueues print job and returns: {"jsonrpc": "2.0", "id": 5, "result": true} // Process cash drawer request const char* cashbox_request = R"({ "jsonrpc": "2.0", "id": 6, "method": "default_printer_action", "params": { "data": { "action": "cashbox" } } })"; std::string cashbox_response = json::PrinterDefaultAction(cashbox_request); // Enqueues cash drawer command and returns: {"jsonrpc": "2.0", "id": 6, "result": true} ``` ## Building the Project ### Build with CMake The project uses CMake and requires Qt6, libjpeg-turbo, zlib, and OpenSSL. The build system supports Windows (MSVC) and Linux platforms. ```bash # Linux build mkdir build && cd build cmake .. make # Required dependencies (Ubuntu/Debian) sudo apt install qt6-base-dev qt6-tools-dev libssl-dev libjpeg-turbo8-dev zlib1g-dev # Windows build (requires Qt 6.5.2 MSVC) mkdir build && cd build cmake -G "Visual Studio 17 2022" -A x64 .. cmake --build . --config Release ``` ## Summary POS Agent Pro serves as a critical middleware component for web-based Point of Sale systems that need to interface with local thermal receipt printers and cash drawers. The primary use case is integration with Odoo POS or similar browser-based retail systems, where the application runs as a local service listening on a configurable HTTP port. When the POS frontend generates a receipt, it renders it as a JPEG image, base64-encodes it, and sends it via JSON-RPC to the hardware proxy, which handles the conversion to ESC/POS commands and physical printing. The modular architecture supports multiple printer backends through a common interface, making it adaptable to various hardware configurations. On Windows, it leverages the print spooler for driver-managed printing, while on Linux it provides both direct USB device access and TCP/IP network printing for ESC/POS compatible thermal printers. The Qt-based GUI offers a system tray presence for unobtrusive operation, with settings for printer selection, image quality (gamma correction), paper width, feed lines, and automatic paper cutting. The event-driven architecture using uWebSockets ensures efficient handling of concurrent requests while the GlobalState singleton provides thread-safe coordination between the network thread and UI components.