Skip to content

Data Persistence

This page aims to guide developers on how to persist data in easy services.

For backend extensions, data should be stored in the data directory under the extension directory. After the extension starts, the system will automatically mount this directory as writable. To ensure data is not lost after extension restart, all data must be stored in this directory. If data is stored in other directories, the extension will not be able to recover this data after restart, resulting in data loss.

Warning

Robot power-off may cause file cache data loss. It is recommended to call the sync command after writing data files to ensure data is flushed to disk.

Example code:

py
import os

os.system("sync")

Data Operation Recommendations

  1. Local file storage: For small data, it is recommended to use file storage solutions such as JSON, SQLite.
  2. Database storage: For more complex data needs, you can choose databases for persistence.

Creating Easy Service Extension Package

In the following example, we will create a easy service type extension. This extension will provide configuration write, configuration read, and configuration delete interfaces, and persist data to SQLite database.

Tip

The DataService mentioned below is the extension name we are about to create.

Step 1: Create Extension Folder

First, we need to create a basic extension folder, which should contain a config.json configuration file and a Python file. Note that in easy services, the Python file name must be the same as the extension name.

You can create it manually from scratch, or modify the template from the "demo" directory in the extension development package repository.

Directory structure:

  • DataService
    • config.json
    • DataService.py
DataService.py
py
from pathlib import Path
import sqlite3

# Get global logger instance, only available in easy services
logger = globals().get('logger')
if logger is None:
    # Use built-in logging library for local debugging
    import logging
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)


def __init_db():
    """
    Initialize database
    """
    try:
        current_dir = Path(__file__).parent.resolve()
        data_dir = current_dir / 'data'

        # If data directory doesn't exist, create it manually
        if not data_dir.exists():
            data_dir.mkdir(parents=True)
        db_path = data_dir / 'data.db'

        # Connect to database
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        logger.info("Database opened successfully")

        # Create table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS `robot_config` (
                `id`            INTEGER PRIMARY KEY AUTOINCREMENT,
                `key`           VARCHAR(255)    NOT NULL UNIQUE,
                `value`         TEXT     NOT NULL
            );
        ''')
        logger.info("Table created successfully")
        conn.commit()

        return conn
    except Exception as e:
        logger.error(f"Failed to initialize database: {e}")
        return None


conn = __init_db()
"""
Global variable to hold the unique database connection instance
"""


def get_robot_config(key: str):
    """Get configuration value by key."""
    try:
        cursor = conn.cursor()
        cursor.execute('SELECT value FROM robot_config WHERE key = ?', (key,))
        result = cursor.fetchone()
        return result[0] if result else None
    except sqlite3.Error as e:
        logger.error(f"Failed to get config '{key}': {e}")
        return None


def set_robot_config(key: str, value: str):
    """Set or update a configuration item."""
    try:
        cursor = conn.cursor()
        cursor.execute('INSERT OR REPLACE INTO robot_config (key, value) VALUES (?, ?)', (key, str(value)))
        conn.commit()
        logger.info(f"Config '{key}' set to '{value}'.")
        return True
    except sqlite3.Error as e:
        logger.error(f"Failed to set config '{key}': {e}")
        return False

def delete_robot_config(key: str):
    """Delete a configuration item by key."""
    try:
        cursor = conn.cursor()
        cursor.execute('DELETE FROM robot_config WHERE key = ?', (key,))
        conn.commit()
        logger.info(f"Config '{key}' deleted.")
        return True
    except sqlite3.Error as e:
        logger.error(f"Failed to delete config '{key}': {e}")
        return False
config.json
json
{
  "name": "DataService",
  "type": "easyService",
  "scriptLang": "python",
  "description": "Data service",
  "version": "0.1"
}

Step 2: Package and Install

For extension packaging, please refer to Package and Install

Step 3: Call Interface

  1. Set Configuration: Access http://10.27.1.254:5616/DataService/set_robot_config?key=model_type&value=GBT-C5A

    This operation will write a configuration item with name model_type and value GBT-C5A .

  2. Get Configuration: Access http://10.27.1.254:5616/DataService/get_robot_config?key=model_type

    Under normal circumstances, it will return:

    json
    {
      "result": "GBT-C5A"
    }
  3. Delete Configuration: Access http://10.27.1.254:5616/DataService/delete_robot_config?key=model_type

    This operation will delete the configuration item model_type .

Note: For more calling methods, please refer to Related Section.