Giter Club home page Giter Club logo

aiovantage's Introduction

aiovantage

aiovantage is a Python library for interacting with and controlling Vantage InFusion home automation controllers.

Uses a controller pattern inspired heavily by the aiohue library.

This open-source, non-commercial library is not affiliated, associated, authorized, endorsed by, or in any way officially connected with Vantage, and is provided for interoperability purposes only.

Table of contents

Example

from aiovantage import Vantage

async with Vantage("192.168.1.2", "username", "password") as vantage:
    async for load in vantage.loads:
        print(f"{load.name} is at {load.level}%")

See the examples folder for more examples.

Features

  • Uses Python asyncio for non-blocking I/O.
  • Exposes "controllers" to make fetching and controlling various objects easy.
  • Uses SSL connections by default, with automatic reconnection.
  • Fetch objects lazily (with async for obj in controller).
  • Alternatively, eager-fetch objects with controller.initialize.

Supported objects types

The following interfaces/controllers are currently supported.

Type Description Controller Examples
AnemoSensor Wind speed sensors vantage.anemo_sensors Examples
Area Rooms, etc vantage.areas Examples
Blind Shades, blinds vantage.blinds Examples
BlindGroups Groups of blinds vantage.blind_groups Examples
Buttons Keypad buttons vantage.buttons Examples
DryContacts Motion sensors, etc vantage.dry_contacts Examples
GMem Vantage variables vantage.gmem Examples
LightSensor Light sensors vantage.light_sensors Examples
Load Lights, relays, etc vantage.loads Examples
LoadGroup Groups of loads vantage.load_groups Examples
Master Vantage controllers vantage.masters Examples
Module Dimmer modules vantage.modules
OmniSensor Power, current, etc vantage.omni_sensors Examples
PowerProfile Load power profiles vantage.power_profiles Examples
RGBLoad RGB lights vantage.rgb_loads Examples
Stations Keypads, etc vantage.stations Examples
Tasks Vantage tasks vantage.tasks Examples
Temperature Temperature sensors vantage.temperature_sensors Examples
Thermostat Thermostats vantage.thermostats Examples

If you have an object that you expect to show up in one of these controllers but is missing, please create an issue or submit a pull request.

Installation

Add aiovantage as a dependency to your project, or install it directly:

pip install aiovantage

Usage

Creating a client

Begin by importing the Vantage class:

from aiovantage import Vantage

The most convenient way to create a client is by using the async context manager:

async with Vantage("hostname", "username", "password") as vantage:
    # ...use the vantage client

Alternatively, you can manage the lifecycle of the client yourself:

from aiovantage import Vantage

vantage = Vantage("hostname", "username", "password")
# ...use the vantage client
vantage.close()

Querying objects

The Vantage class exposes a number of controllers, which can be used to query objects. Controllers can either be populated lazily (by using async for), or eagerly (by using controller.initialize()).

For example, to get a list of all loads:

async with Vantage("hostname", "username", "password") as vantage:
    async for load in vantage.loads:
        print(f"{load.name} is at {load.level}%")

Alternatively, you can use controller.initialize() to eagerly fetch all objects:

async with Vantage("hostname", "username", "password") as vantage:
    await vantage.loads.initialize()
    for load in vantage.loads:
        print(f"{load.name} is at {load.level}%")

If you aren't interested in the state of the objects, you can call controller.initialize(fetch_state=False) to slightly speed up the initialization:

async with Vantage("hostname", "username", "password") as vantage:
    await vantage.loads.initialize(fetch_state=False)
    for load in vantage.loads:
        print(f"{load.name}")

All controllers implement a django-like query interface, which can be used to filter objects. You can either query by matching attributes:

async with Vantage("hostname", "username", "password") as vantage:
    async for load in vantage.loads.filter(name="Kitchen"):
        print(f"{load.name} is at {load.level}%")

Or by using a filter predicate:

async with Vantage("hostname", "username", "password") as vantage:
    async for load in vantage.loads.filter(lambda load: load.level > 50):
        print(f"{load.name} is at {load.level}%")

Fetching a single object

You can fetch a single object by id, by calling controller.aget() or controller.get():

async with Vantage("hostname", "username", "password") as vantage:
    load = await vantage.loads.aget(118)
    print(f"{load.name} is at {load.level}%")

These functions also implement the same query interface as controller.filter() for querying by attributes or filter predicate:

async with Vantage("hostname", "username", "password") as vantage:
    load = await vantage.loads.aget(name="Kitchen")
    print(f"{load.name} is at {load.level}%")

Controlling objects

Most controllers expose a various methods for controlling the state of objects. The first parameter to these methods is always the vantage id of the object to control.

For example, to turn on a load:

async with Vantage("hostname", "username", "password") as vantage:
    await vantage.loads.turn_on(118)

Subscribing to state changes

You can subscribe to state changes by using the controller.subscribe() method:

def on_load_state_change(event, load, data):
    print(f"{load.name} is at {load.level}%")

async with Vantage("hostname", "username", "password") as vantage:
    vantage.loads.subscribe(on_load_state_change)
    await vantage.loads.initialize()

Note that a subscription will only receive state changes for objects that have populated into the controller.

aiovantage's People

Contributors

dependabot[bot] avatar loopj avatar pre-commit-ci[bot] avatar ptr727 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

aiovantage's Issues

Add support for Vantage.Generic_HVAC_RS485_Zone_CHILD thermostat

Checklist

  • This only contains 1 feature request (if you have multiple feature requests, open one feature request for each feature request).
  • This issue is not a duplicate feature request of previous feature requests.

Describe the feature you'd like

I would like to add support for the Vantage.Generic_HVAC_RS485_Zone_CHILD object.
This object functions similarly to the Thermostat object (I have tested with THERMTEMP, GETTHERMTEMP, THERMFAN, GETTHERMFAN, THERMOP , GETTHERMOP, THERMDAY, GETTHERMDAY functions).

However the current Thermostat model inherits from the StationObject model, which includes SerialNumber and Bus fields that are not present in the Vantage.Generic_HVAC_RS485_Zone_CHILD object (you can see an example of the object in the "Additional context" field.

I have created a fork that adds a new model for the Vantage.Generic_HVAC_RS485_Zone_CHILD object. As a quick fix I changed the Thermostat model to inherit from LocationObject instead. This change allows the integration to work correctly.

However I can see that this might not be the best way to implement this as it is modifying existing models. I wanted to get your thoughts on the best way to add support for this object. I can think of 3 solutions:

  1. Just implementing this quick fix
  2. Duplicating the Thermostat classes in the new model
  3. Creating another class that both the Thermostat model and the new model can inherit, which contain the classes from the original Thermostat model

Let me know your thoughts!


Also I just wanted to say thanks for creating this project, I have had a lot of fun working on this! I'm not a software developer, so apologies if this is a simple solution.

Additional context

Here is an example of the Vantage.Generic_HVAC_RS485_Zone_CHILD object.

    <Object>
      <Vantage.Generic_HVAC_RS485_Zone_CHILD VID="{VID}" Master="{MASTER_VID}" MTime="" Position="">
        <Name>{Object_Name}</Name>
        <Model>
        </Model>
        <DeviceCategory>HVAC</DeviceCategory>
        <Note>
        </Note>
        <DName>{Object_DName}</DName>
        <ObjectType>Vantage.Generic_HVAC_RS485_Zone_CHILD</ObjectType>
        <Area>{Area}</Area>
        <Location>
        </Location>
        <Version>
        </Version>
        <Log>None</Log>
        <Parent Position="3">{PARENT_VID}</Parent>
        <IndoorSettings>
          <indoorSensor>0</indoorSensor>
          <IndoorTempOffset>0</IndoorTempOffset>
        </IndoorSettings>
        <PositionNumber>5</PositionNumber>
      </Vantage.Generic_HVAC_RS485_Zone_CHILD>
    </Object>

And here is a link to the fork I have created for this integration:
main...MahirManghnani:aiovantage:main

Received response: "Failed" (Error code 12)

Using main source from v0.2.2.
Running dump_system.py:

2023-06-20 10:41:53,762 [MainThread  ] [DEBUG] Sending command: INVOKE 870 Task.GetState
2023-06-20 10:41:53,773 [MainThread  ] [DEBUG] Received response: CommandResponse(command='INVOKE', args=['870', '1', 'Task.GetState'], data=[])
2023-06-20 10:41:53,775 [MainThread  ] [DEBUG] Sending command: ELLOG STATUS ON
2023-06-20 10:41:53,781 [MainThread  ] [INFO ] TasksController fetched full state
2023-06-20 10:41:53,791 [MainThread  ] [DEBUG] Received response: "Failed" (Error code 12)
2023-06-20 10:41:53,792 [MainThread  ] [DEBUG] Sending command: ELENABLE STATUSEX ON
2023-06-20 10:41:53,808 [MainThread  ] [DEBUG] <asyncio.sslproto.SSLProtocol object at 0x0000025BB0531E50>: Fatal error on transport
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1264.0_x64__qbz5n2kfra8p0\Lib\asyncio\sslproto.py", line 644, in _do_shutdown
    self._sslobj.unwrap()
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1264.0_x64__qbz5n2kfra8p0\Lib\ssl.py", line 983, in unwrap
    return self._sslobj.shutdown()
           ^^^^^^^^^^^^^^^^^^^^^^^
ssl.SSLError: [SSL: APPLICATION_DATA_AFTER_CLOSE_NOTIFY] application data after close notify (_ssl.c:2702)
2023-06-20 10:41:53,813 [MainThread  ] [DEBUG] <_ProactorSocketTransport fd=1028> received EOF
2023-06-20 10:41:53,814 [MainThread  ] [DEBUG] <asyncio.sslproto.SSLProtocol object at 0x0000025BAEF37990> received EOF
2023-06-20 10:41:53,827 [MainThread  ] [DEBUG] Close <ProactorEventLoop running=False closed=False debug=True>

Exception emitted by connection.py:

        # Re-raise all other exceptions, including "R:ERROR" responses
        if isinstance(response, Exception):
            raise response

aiovantage.log

Omni sensors for SDM12 are not reporting sensor values

Checklist

  • This issue only contains 1 issue (if you have multiple issues, open one issue for each issue).
  • This issue is not a duplicate issue of currently previous issues..

Describe the issue

Sensors for SDM12 (temperature, current, power) are not reporting values.

But, as soon as DC is connected, and the SDM12 is selected in the DC UI, the sensors start reporting.
Close DC, or change focus to a different object, and sensors stop reporting again.

I am not 100% sure, but sensors for SDM12 did work when introduced, so may have stopped working some point later.

I noticed this with SDM12's, but it may apply to other omni sensors as well.

I could not confirm if temperature is reported, as DC in v4.6 that I tested with did not show temperature, at least I could not find it in the UI, have not tested with DC 4.7 yet.

Reproduction steps

  • Run monitor_omni_sensors.py, or add SDM12 sensors to HA dashboard.
  • Observe that there are no values reported.
  • Launch DC, connected to controller, focus on a SDM12 module.
  • Observe that sensor values are now reported every few seconds.
  • But only for the selected module.
  • Change DC focus to a different module and observe values now reported for that module.
  • Close DC and sensor values stop being reported.

IDiagnostic.SetFirewallConfiguration() missing brace in API declaration.

Checklist

  • This issue only contains 1 issue (if you have multiple issues, open one issue for each issue).
  • This issue is not a duplicate issue of currently previous issues..

Describe the issue

Looks like a missing closing brace, I can guess where it goes, but I don't know the source of the API declaration, so leaving it to you to fix.

IDiagnostic.SetFirewallConfiguration(OpenPorts: {TCP: List[int], UDP: List[int], ICMP: bool)

Maybe IDiagnostic.SetFirewallConfiguration(OpenPorts: {TCP: List[int], UDP: List[int], ICMP: bool})

Btw, where is this documented?

Reproduction steps

Noticed in VSCode warning about a missing brace.

Add support for Thermostats

Checklist

  • This only contains 1 feature request (if you have multiple feature requests, open one feature request for each feature request).
  • This issue is not a duplicate feature request of previous feature requests.

Describe the feature you'd like

Expose thermostats attached to a Vantage system through a `vantage.thermostats' controller.

Additional context

No response

Child loads for LVRS8-DIN station are not associated with station

Checklist

  • This issue only contains 1 issue (if you have multiple issues, open one issue for each issue).
  • This issue is not a duplicate issue of currently previous issues..

Describe the issue

LVRS8-DIN is detected (thank you), but parent (controller) to child (load) relationship is not reported in HA, i.e. station has no loads and relay loads have no parent.

In contrast DualRelayStation (keypad) and ModuleGen2 (SDM12) does maintain the parent/controller - child/loads relationship in HA.

On reviewing the XML, the LVRS8-DIN and its loads are reported as parent child, just like the DualRelayStation and ModuleGen2.
But, the DualRelayStation has a blackbox parent, regardless, the loads of the DualRelayStation does point directly to the DualRelayStation as parent, same with ModuleGen2.

Reproduction steps

  • Add system with LVRS8-DIN and loads to HA.
  • Observe that LVRS8-DIN and loads are detected.
  • But that there is no parent/child relationship reported in HA.

XML and dump_system.py logs attached for reference.

dump_system.zip
DC46.zip

Re-fetch objects when a "System Program" is detected

Checklist

  • This only contains 1 feature request (if you have multiple feature requests, open one feature request for each feature request).
  • This issue is not a duplicate feature request of previous feature requests.

Describe the feature you'd like

When a new configuration is sent to the controller, it may have added, removed, or changed system objects. We should add support for detecting "system program" events, and update the state of our controllers and/or objects.

We can probably detect a Object.GetMTime and use that.

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.