Skip to content

Commit

Permalink
Add debug support
Browse files Browse the repository at this point in the history
  • Loading branch information
lymanepp committed Feb 8, 2024
1 parent d83e010 commit 0dcf444
Show file tree
Hide file tree
Showing 17 changed files with 1,313 additions and 1 deletion.
53 changes: 53 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Home Assistant",
"type": "python",
"request": "launch",
"module": "homeassistant",
"justMyCode": false,
"args": [
"--debug",
"-c",
"config"
]
},
{
"name": "Python: Debug tests",
"type": "python",
"request": "launch",
"module": "pytest",
"justMyCode": false
},
{
// Example of attaching to local debug server
"name": "Python: Attach Local",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
]
},
{
// Example of attaching to my production server
"name": "Python: Attach Remote",
"type": "python",
"request": "attach",
"port": 5678,
"host": "homeassistant.local",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/usr/src/homeassistant"
}
]
}
]
}
29 changes: 29 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run Home Assistant on port 8123",
"type": "shell",
"command": "container start",
"problemMatcher": []
},
{
"label": "Run Home Assistant configuration against /config",
"type": "shell",
"command": "container check",
"problemMatcher": []
},
{
"label": "Upgrade Home Assistant to latest dev",
"type": "shell",
"command": "container install",
"problemMatcher": []
},
{
"label": "Install a specific version of Home Assistant",
"type": "shell",
"command": "container set-version",
"problemMatcher": []
}
]
}
40 changes: 40 additions & 0 deletions config/configuration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
default_config:

logger:
default: info
logs:
custom_components.keymaster_lite: debug

# If you need to debug uncomment the line below (doc: https://www.home-assistant.io/integrations/debugpy/)
# debugpy:

# https://github.com/twrecked/hass-virtual
virtual:

lock:
- platform: virtual
name: Front Door
initial_availability: true
initial_value: locked
persistent: true

- platform: virtual
name: Back Door
initial_availability: true
initial_value: unlocked
persistent: true

binary_sensor:
- platform: virtual
name: Front Door
class: opening
initial_availability: true
initial_value: "off"
persistent: true

- platform: virtual
name: Back Door
class: opening
initial_availability: true
initial_value: "off"
persistent: true
Empty file added config/packages/placeholder
Empty file.
67 changes: 67 additions & 0 deletions custom_components/virtual/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
This component provides support for virtual components.
"""

import logging
import voluptuous as vol
from distutils import util
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.service import verify_domain_control
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.exceptions import HomeAssistantError

from .const import (
COMPONENT_DOMAIN,
COMPONENT_SERVICES
)

__version__ = '0.8.0b1'

_LOGGER = logging.getLogger(__name__)

SERVICE_AVAILABILE = 'set_available'
SERVICE_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.comp_entity_ids,
vol.Required('value'): cv.boolean,
})


async def async_setup(hass, config):
"""Set up a virtual components."""

hass.data[COMPONENT_SERVICES] = {}
_LOGGER.debug('setup')

@verify_domain_control(hass, COMPONENT_DOMAIN)
async def async_virtual_service_set_available(call) -> None:
"""Call virtual service handler."""
_LOGGER.info("{} service called".format(call.service))
await async_virtual_set_availability_service(hass, call)

hass.services.async_register(COMPONENT_DOMAIN, SERVICE_AVAILABILE, async_virtual_service_set_available)

return True


def get_entity_from_domain(hass, domain, entity_id):
component = hass.data.get(domain)
if component is None:
raise HomeAssistantError("{} component not set up".format(domain))

entity = component.get_entity(entity_id)
if entity is None:
raise HomeAssistantError("{} not found".format(entity_id))

return entity


async def async_virtual_set_availability_service(hass, call):
entity_id = call.data['entity_id']
value = call.data['value']

if not type(value)==bool:
value = bool(util.strtobool(value))
domain = entity_id.split(".")[0]
_LOGGER.info("{} set_avilable(value={})".format(entity_id, value))
get_entity_from_domain(hass, domain, entity_id).set_available(value)
133 changes: 133 additions & 0 deletions custom_components/virtual/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
"""
This component provides support for a virtual binary sensor.
"""

import logging
import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import BinarySensorEntity, DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, ATTR_DEVICE_CLASS
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
from homeassistant.const import STATE_ON

from . import get_entity_from_domain
from .const import (
COMPONENT_DOMAIN,
COMPONENT_SERVICES,
CONF_CLASS,
CONF_INITIAL_VALUE,
)
from .entity import VirtualEntity, virtual_schema


_LOGGER = logging.getLogger(__name__)

DEPENDENCIES = [COMPONENT_DOMAIN]

DEFAULT_INITIAL_VALUE = 'off'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(virtual_schema(DEFAULT_INITIAL_VALUE, {
vol.Optional(CONF_CLASS): cv.string,
}))

SERVICE_ON = 'turn_on'
SERVICE_OFF = 'turn_off'
SERVICE_TOGGLE = 'toggle'
SERVICE_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.comp_entity_ids,
})


async def async_setup_platform(hass, config, async_add_entities, _discovery_info=None):
sensors = [VirtualBinarySensor(config)]
async_add_entities(sensors, True)

async def async_virtual_service(call):
"""Call virtual service handler."""
_LOGGER.debug(f"{call.service} service called")
if call.service == SERVICE_ON:
await async_virtual_on_service(hass, call)
if call.service == SERVICE_OFF:
await async_virtual_off_service(hass, call)
if call.service == SERVICE_TOGGLE:
await async_virtual_toggle_service(hass, call)

# Build up services...
if not hasattr(hass.data[COMPONENT_SERVICES], DOMAIN):
_LOGGER.debug("installing handlers")
hass.data[COMPONENT_SERVICES][DOMAIN] = 'installed'
hass.services.async_register(
COMPONENT_DOMAIN, SERVICE_ON, async_virtual_service, schema=SERVICE_SCHEMA,
)
hass.services.async_register(
COMPONENT_DOMAIN, SERVICE_OFF, async_virtual_service, schema=SERVICE_SCHEMA,
)
hass.services.async_register(
COMPONENT_DOMAIN, SERVICE_TOGGLE, async_virtual_service, schema=SERVICE_SCHEMA,
)


class VirtualBinarySensor(VirtualEntity, BinarySensorEntity):
"""An implementation of a Virtual Binary Sensor."""

def __init__(self, config):
"""Initialize a Virtual Binary Sensor."""
super().__init__(config, DOMAIN)

self._attr_device_class = config.get(CONF_CLASS)

_LOGGER.info('VirtualBinarySensor: %s created', self.name)

def _create_state(self, config):
super()._create_state(config)

self._attr_is_on = config.get(CONF_INITIAL_VALUE).lower() == STATE_ON

def _restore_state(self, state, config):
super()._restore_state(state, config)

self._attr_is_on = state.state.lower() == STATE_ON

def _update_attributes(self):
super()._update_attributes();
self._attr_extra_state_attributes.update({
name: value for name, value in (
(ATTR_DEVICE_CLASS, self._attr_device_class),
) if value is not None
})

def turn_on(self) -> None:
_LOGGER.debug(f"turning {self.name} on")
self._attr_is_on = True
self.async_schedule_update_ha_state()

def turn_off(self) -> None:
_LOGGER.debug(f"turning {self.name} off")
self._attr_is_on = False
self.async_schedule_update_ha_state()

def toggle(self) -> None:
if self.is_on:
self.turn_off()
else:
self.turn_on()


async def async_virtual_on_service(hass, call):
for entity_id in call.data['entity_id']:
_LOGGER.debug(f"turning on {entity_id}")
get_entity_from_domain(hass, DOMAIN, entity_id).turn_on()


async def async_virtual_off_service(hass, call):
for entity_id in call.data['entity_id']:
_LOGGER.debug(f"turning off {entity_id}")
get_entity_from_domain(hass, DOMAIN, entity_id).turn_off()


async def async_virtual_toggle_service(hass, call):
for entity_id in call.data['entity_id']:
_LOGGER.debug(f"toggling {entity_id}")
get_entity_from_domain(hass, DOMAIN, entity_id).toggle()
14 changes: 14 additions & 0 deletions custom_components/virtual/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Constants for the virtual component. """

COMPONENT_DOMAIN = 'virtual'
COMPONENT_SERVICES = 'virtual-services'

CONF_CLASS = "class"
CONF_INITIAL_AVAILABILITY = "initial_availability"
CONF_INITIAL_VALUE = "initial_value"
CONF_NAME = "name"
CONF_PERSISTENT = "persistent"

DEFAULT_INITIAL_AVAILABILITY = True
DEFAULT_PERSISTENT = True

Loading

0 comments on commit 0dcf444

Please sign in to comment.