* Add a component for GreenEye Monitor [GreenEye Monitor](http://www.brultech.com/greeneye/) is an energy monitor that can monitor emergy usage of individual circuits, count pulses from things like water or gas meters, and monitor temperatures. This component exposes these various sensors in Home Assistant, for both data tracking and automation triggering purposes. * Consolidate sensors * lint * .coveragerc * - cv.ensure_list - DOMAIN, where appropriate - defaults to schema - single invocation of async_load_platform - async_create_task instead of async_add_job - fail if no sensors - monitors required - async_add_entities - call add_devices once - remove unused schema - use properties rather than set fields - move _number and unique_id to GEMSensor - remove unnecessary get(xxx, None) - keep params on one line when possible - new-style string format * Fix `ensure_list` usage, log message * Pass config through
171 lines
5.1 KiB
Python
171 lines
5.1 KiB
Python
"""
|
|
Support for monitoring a GreenEye Monitor energy monitor.
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
https://home-assistant.io/components/greeneye_monitor/
|
|
"""
|
|
import logging
|
|
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.const import (
|
|
CONF_NAME,
|
|
CONF_PORT,
|
|
CONF_TEMPERATURE_UNIT,
|
|
EVENT_HOMEASSISTANT_STOP)
|
|
import homeassistant.helpers.config_validation as cv
|
|
from homeassistant.helpers.discovery import async_load_platform
|
|
|
|
REQUIREMENTS = ['greeneye_monitor==0.1']
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
CONF_CHANNELS = 'channels'
|
|
CONF_COUNTED_QUANTITY = 'counted_quantity'
|
|
CONF_COUNTED_QUANTITY_PER_PULSE = 'counted_quantity_per_pulse'
|
|
CONF_MONITOR_SERIAL_NUMBER = 'monitor'
|
|
CONF_MONITORS = 'monitors'
|
|
CONF_NET_METERING = 'net_metering'
|
|
CONF_NUMBER = 'number'
|
|
CONF_PULSE_COUNTERS = 'pulse_counters'
|
|
CONF_SERIAL_NUMBER = 'serial_number'
|
|
CONF_SENSORS = 'sensors'
|
|
CONF_SENSOR_TYPE = 'sensor_type'
|
|
CONF_TEMPERATURE_SENSORS = 'temperature_sensors'
|
|
CONF_TIME_UNIT = 'time_unit'
|
|
|
|
DATA_GREENEYE_MONITOR = 'greeneye_monitor'
|
|
DOMAIN = 'greeneye_monitor'
|
|
|
|
SENSOR_TYPE_CURRENT = 'current_sensor'
|
|
SENSOR_TYPE_PULSE_COUNTER = 'pulse_counter'
|
|
SENSOR_TYPE_TEMPERATURE = 'temperature_sensor'
|
|
|
|
TEMPERATURE_UNIT_CELSIUS = 'C'
|
|
|
|
TIME_UNIT_SECOND = 's'
|
|
TIME_UNIT_MINUTE = 'min'
|
|
TIME_UNIT_HOUR = 'h'
|
|
|
|
TEMPERATURE_SENSOR_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_NUMBER): vol.Range(1, 8),
|
|
vol.Required(CONF_NAME): cv.string,
|
|
})
|
|
|
|
TEMPERATURE_SENSORS_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
|
|
vol.Required(CONF_SENSORS): vol.All(cv.ensure_list,
|
|
[TEMPERATURE_SENSOR_SCHEMA]),
|
|
})
|
|
|
|
PULSE_COUNTER_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_NUMBER): vol.Range(1, 4),
|
|
vol.Required(CONF_NAME): cv.string,
|
|
vol.Required(CONF_COUNTED_QUANTITY): cv.string,
|
|
vol.Optional(
|
|
CONF_COUNTED_QUANTITY_PER_PULSE, default=1.0): vol.Coerce(float),
|
|
vol.Optional(CONF_TIME_UNIT, default=TIME_UNIT_SECOND): vol.Any(
|
|
TIME_UNIT_SECOND,
|
|
TIME_UNIT_MINUTE,
|
|
TIME_UNIT_HOUR),
|
|
})
|
|
|
|
PULSE_COUNTERS_SCHEMA = vol.All(cv.ensure_list, [PULSE_COUNTER_SCHEMA])
|
|
|
|
CHANNEL_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_NUMBER): vol.Range(1, 48),
|
|
vol.Required(CONF_NAME): cv.string,
|
|
vol.Optional(CONF_NET_METERING, default=False): cv.boolean,
|
|
})
|
|
|
|
CHANNELS_SCHEMA = vol.All(cv.ensure_list, [CHANNEL_SCHEMA])
|
|
|
|
MONITOR_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_SERIAL_NUMBER): cv.positive_int,
|
|
vol.Optional(CONF_CHANNELS, default=[]): CHANNELS_SCHEMA,
|
|
vol.Optional(
|
|
CONF_TEMPERATURE_SENSORS,
|
|
default={
|
|
CONF_TEMPERATURE_UNIT: TEMPERATURE_UNIT_CELSIUS,
|
|
CONF_SENSORS: [],
|
|
}): TEMPERATURE_SENSORS_SCHEMA,
|
|
vol.Optional(CONF_PULSE_COUNTERS, default=[]): PULSE_COUNTERS_SCHEMA,
|
|
})
|
|
|
|
MONITORS_SCHEMA = vol.All(cv.ensure_list, [MONITOR_SCHEMA])
|
|
|
|
COMPONENT_SCHEMA = vol.Schema({
|
|
vol.Required(CONF_PORT): cv.port,
|
|
vol.Required(CONF_MONITORS): MONITORS_SCHEMA,
|
|
})
|
|
|
|
CONFIG_SCHEMA = vol.Schema({
|
|
DOMAIN: COMPONENT_SCHEMA,
|
|
}, extra=vol.ALLOW_EXTRA)
|
|
|
|
|
|
async def async_setup(hass, config):
|
|
"""Set up the GreenEye Monitor component."""
|
|
from greeneye import Monitors
|
|
|
|
monitors = Monitors()
|
|
hass.data[DATA_GREENEYE_MONITOR] = monitors
|
|
|
|
server_config = config[DOMAIN]
|
|
server = await monitors.start_server(server_config[CONF_PORT])
|
|
|
|
async def close_server(*args):
|
|
"""Close the monitoring server."""
|
|
await server.close()
|
|
|
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_server)
|
|
|
|
all_sensors = []
|
|
for monitor_config in server_config[CONF_MONITORS]:
|
|
monitor_serial_number = {
|
|
CONF_MONITOR_SERIAL_NUMBER: monitor_config[CONF_SERIAL_NUMBER],
|
|
}
|
|
|
|
channel_configs = monitor_config[CONF_CHANNELS]
|
|
for channel_config in channel_configs:
|
|
all_sensors.append({
|
|
CONF_SENSOR_TYPE: SENSOR_TYPE_CURRENT,
|
|
**monitor_serial_number,
|
|
**channel_config,
|
|
})
|
|
|
|
sensor_configs = \
|
|
monitor_config[CONF_TEMPERATURE_SENSORS]
|
|
if sensor_configs:
|
|
temperature_unit = {
|
|
CONF_TEMPERATURE_UNIT: sensor_configs[CONF_TEMPERATURE_UNIT],
|
|
}
|
|
for sensor_config in sensor_configs[CONF_SENSORS]:
|
|
all_sensors.append({
|
|
CONF_SENSOR_TYPE: SENSOR_TYPE_TEMPERATURE,
|
|
**monitor_serial_number,
|
|
**temperature_unit,
|
|
**sensor_config,
|
|
})
|
|
|
|
counter_configs = monitor_config[CONF_PULSE_COUNTERS]
|
|
for counter_config in counter_configs:
|
|
all_sensors.append({
|
|
CONF_SENSOR_TYPE: SENSOR_TYPE_PULSE_COUNTER,
|
|
**monitor_serial_number,
|
|
**counter_config,
|
|
})
|
|
|
|
if not all_sensors:
|
|
_LOGGER.error("Configuration must specify at least one "
|
|
"channel, pulse counter or temperature sensor")
|
|
return False
|
|
|
|
hass.async_create_task(async_load_platform(
|
|
hass,
|
|
'sensor',
|
|
DOMAIN,
|
|
all_sensors,
|
|
config))
|
|
|
|
return True
|