Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed home assistant tests #3136

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ Registry Configuration
+++++++++++++++++++++++

Registry file can contain one single device and its attributes or a logical group of devices and its
attributes. Each entry should include the full entity id of the device, including but not limited to home assistant provided prefix
attributes. Each entry should include the full entity id of the device, including but not limited to home assistant provided prefix
such as "light.", "climate." etc. The driver uses these prefixes to convert states into integers.
Like mentioned before, the driver can only control lights and thermostats but can get data from all devices
controlled by home assistant

Each entry in a registry file should also have a 'Entity Point' and a unique value for 'Volttron Point Name'. The 'Entity ID' maps to the device instance, the 'Entity Point' extracts the attribute or state, and 'Volttron Point Name' determines the name of that point as it appears in VOLTTRON.

Attributes can be located in the developer tools in the Home Assistant GUI.
Expand Down Expand Up @@ -108,7 +108,7 @@ id 'light.example':
.. note::

When using a single registry file to represent a logical group of multiple physical entities, make sure the
"Volttron Point Name" is unique within a single registry file.
"Volttron Point Name" is unique within a single registry file.

For example, if a registry file contains entities with
id 'light.instance1' and 'light.instance2' the entry for the attribute brightness for these two light instances could
Expand Down Expand Up @@ -175,3 +175,12 @@ Upon completion, initiate the platform driver. Utilize the listener agent to ver
[{'light_brightness': 254, 'state': 'on'},
{'light_brightness': {'type': 'integer', 'tz': 'UTC', 'units': 'int'},
'state': {'type': 'integer', 'tz': 'UTC', 'units': 'On / Off'}}]

Running Tests
+++++++++++++++++++++++
To run tests on the VOLTTRON home assistant driver you need to create a helper in your home assistant instance. This can be done by going to **Settings > Devices & services > Helpers > Create Helper > Toggle**. Name this new toggle **volttrontest**. After that run the pytest from the root of your VOLTTRON file.

.. code-block:: bash
pytest volttron/services/core/PlatformDriverAgent/tests/test_home_assistant.py

If everything works, you will see 6 passed tests.
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
# -*- coding: utf-8 -*- {{{
# ===----------------------------------------------------------------------===
# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et:
#
# Component of Eclipse VOLTTRON
# Copyright 2020, Battelle Memorial Institute.
#
# ===----------------------------------------------------------------------===
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# Copyright 2023 Battelle Memorial Institute
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ===----------------------------------------------------------------------===
# This material was prepared as an account of work sponsored by an agency of
# the United States Government. Neither the United States Government nor the
# United States Department of Energy, nor Battelle, nor any of their
# employees, nor any jurisdiction or organization that has cooperated in the
# development of these materials, makes any warranty, express or
# implied, or assumes any legal liability or responsibility for the accuracy,
# completeness, or usefulness or any information, apparatus, product,
# software, or process disclosed, or represents that its use would not infringe
# privately owned rights. Reference herein to any specific commercial product,
# process, or service by trade name, trademark, manufacturer, or otherwise
# does not necessarily constitute or imply its endorsement, recommendation, or
# favoring by the United States Government or any agency thereof, or
# Battelle Memorial Institute. The views and opinions of authors expressed
# herein do not necessarily state or reflect those of the
# United States Government or any agency thereof.
#
# PACIFIC NORTHWEST NATIONAL LABORATORY operated by
# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY
# under Contract DE-AC05-76RL01830
# }}}


Expand All @@ -28,7 +42,7 @@
import json
import sys
from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert
from volttron.platform.agent import utils # added this to pull from config store
from volttron.platform.agent import utils
from volttron.platform.vip.agent import Agent
import logging
import requests
Expand Down Expand Up @@ -80,7 +94,7 @@ def __init__(self, **kwargs):
self.port = None
self.units = None

def configure(self, config_dict, registry_config_str): # grabbing from config
def configure(self, config_dict, registry_config_str):
self.ip_address = config_dict.get("ip_address", None)
self.access_token = config_dict.get("access_token", None)
self.port = config_dict.get("port", None)
Expand Down Expand Up @@ -141,6 +155,20 @@ def _set_point(self, point_name, value):
_log.error(error_msg)
raise ValueError(error_msg)

elif "input_boolean." in register.entity_id:
if entity_point == "state":
if isinstance(register.value, int) and register.value in [0, 1]:
if register.value == 1:
self.set_input_boolean(register.entity_id, "on")
elif register.value == 0:
self.set_input_boolean(register.entity_id, "off")
else:
error_msg = f"State value for {register.entity_id} should be an integer value of 1 or 0"
_log.info(error_msg)
raise ValueError(error_msg)
else:
_log.info(f"Currently, input_booleans only support state")

# Changing thermostat values.
elif "climate." in register.entity_id:
if entity_point == "state":
Expand Down Expand Up @@ -200,7 +228,6 @@ def _scrape_all(self):
if "climate." in entity_id: # handling thermostats.
if entity_point == "state":
state = entity_data.get("state", None)

# Giving thermostat states an equivalent number.
if state == "off":
register.value = 0
Expand All @@ -224,7 +251,7 @@ def _scrape_all(self):
register.value = attribute
result[register.point_name] = attribute
# handling light states
elif "light." in entity_id:
elif "light." or "input_boolean." in entity_id: # Checks for lights or input bools since they have the same states.
if entity_point == "state":
state = entity_data.get("state", None)
# Converting light states to numbers.
Expand Down Expand Up @@ -269,10 +296,7 @@ def parse_config(self, config_dict):
self.point_name = regDef['Volttron Point Name']
self.units = regDef['Units']
description = regDef.get('Notes', '')

default_value = str(regDef.get("Starting Value", 'sin')).strip()
if not default_value:
default_value = None
default_value = ("Starting Value")
type_name = regDef.get("Type", 'string')
reg_type = type_mapping.get(type_name, str)
attributes = regDef.get('Attributes', {})
Expand Down Expand Up @@ -375,3 +399,23 @@ def change_brightness(self, entity_id, value):
}

_post_method(url, headers, payload, f"set brightness of {entity_id} to {value}")

def set_input_boolean(self, entity_id, state):
service = 'turn_on' if state == 'on' else 'turn_off'
url = f"http://{self.ip_address}:{self.port}/api/services/input_boolean/{service}"
headers = {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json",
}

payload = {
"entity_id": entity_id
}

response = requests.post(url, headers=headers, json=payload)

# Optionally check for a successful response
if response.status_code == 200:
print(f"Successfully set {entity_id} to {state}")
else:
print(f"Failed to set {entity_id} to {state}: {response.text}")
62 changes: 39 additions & 23 deletions services/core/PlatformDriverAgent/tests/test_home_assistant.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
# -*- coding: utf-8 -*- {{{
# ===----------------------------------------------------------------------===
# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et:
#
# Component of Eclipse VOLTTRON
# Copyright 2020, Battelle Memorial Institute.
#
# ===----------------------------------------------------------------------===
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# Copyright 2023 Battelle Memorial Institute
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This material was prepared as an account of work sponsored by an agency of
# the United States Government. Neither the United States Government nor the
# United States Department of Energy, nor Battelle, nor any of their
# employees, nor any jurisdiction or organization that has cooperated in the
# development of these materials, makes any warranty, express or
# implied, or assumes any legal liability or responsibility for the accuracy,
# completeness, or usefulness or any information, apparatus, product,
# software, or process disclosed, or represents that its use would not infringe
# privately owned rights. Reference herein to any specific commercial product,
# process, or service by trade name, trademark, manufacturer, or otherwise
# does not necessarily constitute or imply its endorsement, recommendation, or
# favoring by the United States Government or any agency thereof, or
# Battelle Memorial Institute. The views and opinions of authors expressed
# herein do not necessarily state or reflect those of the
# United States Government or any agency thereof.
#
# ===----------------------------------------------------------------------===
# PACIFIC NORTHWEST NATIONAL LABORATORY operated by
# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY
# under Contract DE-AC05-76RL01830
# }}}

import json
import logging
import pytest
Expand All @@ -38,7 +53,8 @@
utils.setup_logging()
logger = logging.getLogger(__name__)

HOMEASSISTANT_DEVICE_TOPIC = "devices/home_assistant"
# To run these tests, create a helper toggle named volttrontest in your Home Assistant instance.
# This can be done by going to Settings > Devices & services > Helpers > Create Helper > Toggle
HOMEASSISTANT_TEST_IP = ""
ACCESS_TOKEN = ""
PORT = ""
Expand All @@ -57,14 +73,14 @@
def test_get_point(volttron_instance, config_store):
expected_values = 0
agent = volttron_instance.dynamic_agent
result = agent.vip.rpc.call(PLATFORM_DRIVER, 'get_point', 'home_assistant', 'light_state').get(timeout=20)
result = agent.vip.rpc.call(PLATFORM_DRIVER, 'get_point', 'home_assistant', 'bool_state').get(timeout=20)
assert result == expected_values, "The result does not match the expected result."


# The default value for this fake light is 3. If the test cannot reach out to home assistant,
# the value will default to 3 meking the test fail.
# the value will default to 3 making the test fail.
def test_data_poll(volttron_instance: PlatformWrapper, config_store):
expected_values = [{'light_state': 0}, {'light_state': 1}]
expected_values = [{'bool_state': 0}, {'bool_state': 1}]
agent = volttron_instance.dynamic_agent
result = agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', 'home_assistant').get(timeout=20)
assert result in expected_values, "The result does not match the expected result."
Expand All @@ -73,9 +89,9 @@ def test_data_poll(volttron_instance: PlatformWrapper, config_store):
# Turn on the light. Light is automatically turned off every 30 seconds to allow test to turn
# it on and receive the correct value.
def test_set_point(volttron_instance, config_store):
expected_values = {'light_state': 1}
expected_values = {'bool_state': 1}
agent = volttron_instance.dynamic_agent
agent.vip.rpc.call(PLATFORM_DRIVER, 'set_point', 'home_assistant', 'light_state', 1)
agent.vip.rpc.call(PLATFORM_DRIVER, 'set_point', 'home_assistant', 'bool_state', 1)
gevent.sleep(10)
result = agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', 'home_assistant').get(timeout=20)
assert result == expected_values, "The result does not match the expected result."
Expand All @@ -89,9 +105,9 @@ def config_store(volttron_instance, platform_driver):

registry_config = "homeassistant_test.json"
registry_obj = [{
"Entity ID": "light.fake_light",
"Entity ID": "input_boolean.volttrontest",
"Entity Point": "state",
"Volttron Point Name": "light_state",
"Volttron Point Name": "bool_state",
"Units": "On / Off",
"Units Details": "off: 0, on: 1",
"Writable": True,
Expand Down
Loading