Connecting

Opening the connection

pyplumio.open_tcp_connection(host: str, port: int, *, protocol: Protocol | None = None, reconnect_on_failure: bool = True, **kwargs: Any) TcpConnection

Create a TCP connection.

Parameters:
  • host (str) – IP address or host name of the remote RS-485 server

  • port (int) – Port that remote RS-485 server is listening to

  • protocol (Protocol, optional) – Protocol that will be used for communication with the ecoMAX controller, default to AsyncProtocol

  • reconnect_on_failure (bool, optional) – True if PyPlumIO should try reconnecting on failure, otherwise False, default to True

  • **kwargs – Additional keyword arguments to be passed to asyncio.open_connection()

Returns:

An instance of TCP connection

Return type:

TcpConnection

With this you can connect to the controller remotely via RS-485 to Ethernet/WiFi converters, which are readily available online or can be custom built using wired connection and ser2net software.

import pyplumio

async with pyplumio.open_tcp_connection("localhost", port=8899) as conn:
    ...

Note

Although async with syntax is preferred, you can initiate connection without it. See following examples for more information.

pyplumio.open_serial_connection(device: str, baudrate: int = 115200, *, protocol: Protocol | None = None, reconnect_on_failure: bool = True, **kwargs: Any) SerialConnection

Create a serial connection.

Parameters:
  • device (str) – Serial port device name. e. g. /dev/ttyUSB0

  • baudrate (int, optional) – Serial port baud rate, defaults to 115200

  • protocol (Protocol, optional) – Protocol that will be used for communication with the ecoMAX controller, default to AsyncProtocol

  • reconnect_on_failure (bool, optional) – True if PyPlumIO should try reconnecting on failure, otherwise False, default to True

  • **kwargs – Additional keyword arguments to be passed to serial_asyncio.open_serial_connection()

Returns:

An instance of serial connection

Return type:

SerialConnection

You can connect to the ecoMAX controller via wired connection through RS-485 to USB or RS-485 to TTL adapters, that are connected directly to the device running PyPlumIO.

You MUST not connect RS-485 lines directly to the UART outputs of your PC or you’ll risk damaging your PC/controller or the ecoMAX controller itself.

import pyplumio

async with pyplumio.open_serial_connection("/dev/ttyUSB0", baudrate=115200) as conn:
    ...

Protocols

Connection helpers and classes allow to specify custom protocol to handle data, once connection is established.

All protocols should inherit following abstract base class:

class pyplumio.Protocol

Represents a protocol.

Most of documentation assumes that protocol is left as is, which is by default AsyncProtocol. However, setting different protocol allows for more fine-grained control over data processing.

In following example we’ll set protocol to DummyProtocol, request and output alerts and close the connection without an additional overhead of working with device classes and queues.

import asyncio

import pyplumio
from pyplumio.const import DeviceType
from pyplumio.frames import requests, responses


async def main():
    """Open a connection and request alerts."""
    async with pyplumio.open_tcp_connection(
        host="localhost", port=8899, protocol=pyplumio.DummyProtocol()
    ) as connection:
        await connection.writer.write(
            requests.AlertsRequest(recipient=DeviceType.ECOMAX, start=0, count=5)
        )

        while connection.connected:
            try:
                if isinstance(
                    (frame := await connection.reader.read()), responses.AlertsResponse
                ):
                    print(frame.data)
                    break
            except pyplumio.ProtocolError:
                # Skip protocol errors and read the next frame.
                pass


asyncio.run(main())

All built-in protocols are listed below.

class pyplumio.DummyProtocol

Represents a dummy protocol.

This protocol sets frame reader and writer as attributes, then sets connected event and does nothing.

class pyplumio.AsyncProtocol(ethernet_parameters: EthernetParameters | None = None, wireless_parameters: WirelessParameters | None = None, consumers_count: int = 3)

Represents an async protocol.

This protocol implements producer-consumers pattern using asyncio queues.

The frame producer tries to read frames from the write queue. If any is available, it sends them to the device via frame writer.

It then reads stream via frame reader and puts received frame into the read queue.

Frame consumers read frames from the read queue, create device entry, if needed, and send frame to the entry for the processing.

Network Information

When opening the connection, you can send ethernet and wireless network information to the ecoMAX controller by passing one or both of data classes below to the Protocol of your choice.

class pyplumio.EthernetParameters(ip: str = '0.0.0.0', netmask: str = '255.255.255.0', gateway: str = '0.0.0.0', status: bool = True)

Represents an ethernet parameters.

gateway: str = '0.0.0.0'

Gateway IP address

ip: str = '0.0.0.0'

IP address

netmask: str = '255.255.255.0'

IP subnet mask

status: bool = True

Connection status. Parameters will be ignored if set to False

class pyplumio.WirelessParameters(ip: str = '0.0.0.0', netmask: str = '255.255.255.0', gateway: str = '0.0.0.0', status: bool = True, ssid: str = '', encryption: EncryptionType = EncryptionType.NONE, signal_quality: int = 100)

Represents a wireless network parameters.

status: bool = True

Connection status. Parameters will be ignored if set to False

encryption: EncryptionType = 1

Wireless encryption standard (0 - unknown, 1 - no encryption, 2 - WEP, 3 - WPA, 4 - WPA2)

signal_quality: int = 100

Wireless signal strength in percentage

ssid: str = ''

Wireless Service Set IDentifier

Once set, network information will be shown in information section on the ecoMAX panel.

In the example below, we’ll set both ethernet and wireless parameters.

import pyplumio
from pyplumio.const import EncryptionType


async def main():
    """Initialize a connection with network parameters."""
    async with pyplumio.open_tcp_connection(
        host="localhost",
        port=8899,
        protocol=pyplumio.AsyncProtocol(
            ethernet_parameters=pyplumio.EthernetParameters(
                ip="10.10.1.100",
                netmask="255.255.255.0",
                gateway="10.10.1.1",
            ),
            wireless_parameters=pyplumio.WirelessParameters(
                ip="10.10.2.100",
                netmask="255.255.255.0",
                gateway="10.10.2.1",
                ssid="My SSID",
                encryption=EncryptionType.WPA2,
                signal_quality=100,
            ),
        ),
    ) as connection:
        ...

Connection Examples

The following example illustrates opening a TCP connection using Python’s context manager.

import asyncio
import logging

import pyplumio


_LOGGER = logging.getLogger(__name__)


async def main():
    """Opens the connection and gets the ecoMAX device."""
    async with pyplumio.open_tcp_connection("localhost", port=8899) as conn:
        try:
            # Get the ecoMAX device within 10 seconds or timeout.
            ecomax = await conn.get("ecomax", timeout=10)
        except asyncio.TimeoutError:
            # If device times out, log the error.
            _LOGGER.error("Failed to get the device within 10 seconds")


# Run the coroutine in asyncio event loop.
asyncio.run(main())

The following example illustrates opening a TCP connection without using Python’s context manager.

import asyncio
import logging

import pyplumio


_LOGGER = logging.getLogger(__name__)


async def main():
    """Opens the connection and gets the ecoMAX device."""
    connection = pyplumio.open_tcp_connection("localhost", port=8899)

    # Connect to the device.
    await connection.connect()

    try:
        # Get the ecoMAX device within 10 seconds or timeout.
        ecomax = await connection.get("ecomax", timeout=10)
    except asyncio.TimeoutError:
        # If device times out, log the error.
        _LOGGER.error("Failed to get the device within 10 seconds")

    # Close the connection.
    await connection.close()


# Run the coroutine in asyncio event loop.
asyncio.run(main())