External Programs

The MeterVision program achieves maximum efficiency when used in combination with other programs capable of processing machine vision recognition results. For example, such a program can be METLAB or user-written software.

For this purpose, the program can send recognition results to external programs in two ways (files in output and a socket server; enable the modes in Recognition results).

It is also possible to control certain MeterVision functions from external programs in two ways:

  1. Via the text file input/command.txt in the Program Directory.

  2. Over a socket (if “Send results over socket” is enabled in Settings) — using the same command syntax; each command on a separate line; the server replies with OK / ERROR: ... (or with results for the get command).

You can send several commands at once in the file or over the socket: each command on a separate line. Commands are executed from the first line to the last.

The following commands are available:

  1. Close the MeterVision program

exit
  1. Save a Screenshot

  • To the default folder (output/screenshots/ in Program Directory) with the default file name (creation date and time)

screenshot
  • To the default folder with a custom file name

screenshot my_name.png
  • To a specified folder with a custom file name

screenshot path/to/my/dir/my_name.png
  1. Open a zone settings file

open path/to/my/dir/settings.mv
  1. Fix the background (pointer methods only)

fix_background n

Where n is the target zone number

  1. Remove the background fixation (pointer methods only)

unfix_background n

Where n is the target zone number

  1. Fix the center (pointer methods only)

fix_center n

Where n is the target zone number

  1. Remove the center fixation (pointer methods only)

unfix_center n

Where n is the target zone number

  1. Forget the zone statistics (pointer methods only)

forget_stats n

Where n is the target zone number

  1. Forget the background (pointer methods only)

forget_background n

Where n is the target zone number

  1. Switch to another scale (pointer methods only)

scale n m

Where n is the target zone number and m is the index of the scale to switch to

  1. Switch the result display mode (pointer methods only)

  • Result is the scale reading

result_mode n scale
  • Result is the pointer inclination angle (in degrees)

result_mode n angle

Where n is the target zone number

Example input/command.txt file

screenshot my_name.png
unfix_background 1
fix_center 1
scale 1 3
result_mode 1 angle

Sending commands and results over socket

When the socket mode is enabled (see Recognition results), an external program connects to the host/port from input/socket_config.txt and sends text lines ending with a newline.

The command and reply separator is a newline. Several commands can be sent in one connection; the server replies with one line per command (for get — a results line like {1: '24.10', 2: 'AC'}, for other commands — OK or ERROR: ...).

  • get or results — get the current recognition results (one reply per request; the command can be repeated as many times as needed on the same connection).

  • Any command from the list above — perform the action; reply OK or ERROR: ....

Example command sequence:

get
fix_center 1
scale 1 2

Example of requesting results (examples/socket_results_example.py). You can call get_results() multiple times on the same connection:

import socket
import time


class MeterVisionClient:
    def __init__(self, host='localhost', port=65432):
        self.host = host
        self.port = port
        self.sock = None
        self._buffer = ''

    def connect(self):
        """Connect to the MeterVision server."""
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.host, self.port))
        self._buffer = ''
        print(f"Connected to server {self.host}:{self.port}")

    def get_results(self):
        """
        Request current results. Can be called repeatedly on the same
        connection. Returns a string like "{1: '24.10', 2: 'AC'}".
        """
        if self.sock is None:
            raise RuntimeError('Call connect() first')

        self.sock.sendall(b'get\n')
        while '\n' not in self._buffer:
            chunk = self.sock.recv(4096)
            if not chunk:
                raise ConnectionError('Server closed the connection')
            self._buffer += chunk.decode('utf-8')
        line, self._buffer = self._buffer.split('\n', 1)
        return line

    def close(self):
        """Close the connection."""
        if self.sock is not None:
            self.sock.close()
            self.sock = None
            print('Connection closed')


if __name__ == "__main__":
    client = MeterVisionClient()
    try:
        client.connect()
        for i in range(5):
            results = client.get_results()
            print(f"[{i + 1}] Received:", results)
            time.sleep(1)
    except ConnectionRefusedError as e:
        print(e)
    except KeyboardInterrupt:
        print('Connection interrupted')
    finally:
        client.close()

Example of sending commands (examples/socket_commands_example.py):

import socket


def send_commands(commands, host='localhost', port=65432):
    """
    Sends a list of commands and prints server replies.

    Args:
        commands: list of command strings without a trailing \\n
        host, port: MeterVision server address
    """
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        client_socket.connect((host, port))
        print(f"Connected to server {host}:{port}")
    except ConnectionRefusedError as e:
        print(e)
        return

    try:
        payload = ''.join(cmd.strip() + '\n' for cmd in commands if cmd.strip())
        client_socket.sendall(payload.encode('utf-8'))

        buffer = ''
        replies_expected = sum(1 for cmd in commands if cmd.strip())
        replies_got = 0

        while replies_got < replies_expected:
            data = client_socket.recv(4096)
            if not data:
                break
            buffer += data.decode('utf-8')
            while '\n' in buffer:
                line, buffer = buffer.split('\n', 1)
                print("Reply:", line)
                replies_got += 1
                if replies_got >= replies_expected:
                    break

    except KeyboardInterrupt:
        print('Connection interrupted')

    finally:
        client_socket.close()


if __name__ == "__main__":
    # Example: request results and run commands for a pointer zone
    send_commands([
        'get',
        'fix_center 1',
        'result_mode 1 scale',
    ])

Note

These examples are also available as examples/socket_results_example.py and examples/socket_commands_example.py relative to the program installation directory.