mirror of
https://github.com/esphome/esphome.git
synced 2025-09-15 01:32:19 +01:00
add-black (#1593)
* Add black Update pre commit Update pre commit add empty line * Format with black
This commit is contained in:
committed by
GitHub
parent
2b60b0f1fa
commit
69879920eb
@@ -4,23 +4,64 @@ import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.components import mqtt
|
||||
from esphome.const import CONF_DEVICE_CLASS, CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, \
|
||||
CONF_BELOW, CONF_EXPIRE_AFTER, CONF_FILTERS, CONF_FROM, CONF_ICON, CONF_ID, CONF_INTERNAL, \
|
||||
CONF_ON_RAW_VALUE, CONF_ON_VALUE, CONF_ON_VALUE_RANGE, CONF_SEND_EVERY, CONF_SEND_FIRST_AT, \
|
||||
CONF_TO, CONF_TRIGGER_ID, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE, CONF_NAME, CONF_MQTT_ID, \
|
||||
CONF_FORCE_UPDATE, UNIT_EMPTY, ICON_EMPTY, DEVICE_CLASS_EMPTY, DEVICE_CLASS_BATTERY, \
|
||||
DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, \
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_POWER, \
|
||||
DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLTAGE
|
||||
from esphome.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ABOVE,
|
||||
CONF_ACCURACY_DECIMALS,
|
||||
CONF_ALPHA,
|
||||
CONF_BELOW,
|
||||
CONF_EXPIRE_AFTER,
|
||||
CONF_FILTERS,
|
||||
CONF_FROM,
|
||||
CONF_ICON,
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_ON_RAW_VALUE,
|
||||
CONF_ON_VALUE,
|
||||
CONF_ON_VALUE_RANGE,
|
||||
CONF_SEND_EVERY,
|
||||
CONF_SEND_FIRST_AT,
|
||||
CONF_TO,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_WINDOW_SIZE,
|
||||
CONF_NAME,
|
||||
CONF_MQTT_ID,
|
||||
CONF_FORCE_UPDATE,
|
||||
UNIT_EMPTY,
|
||||
ICON_EMPTY,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
)
|
||||
from esphome.core import CORE, coroutine, coroutine_with_priority
|
||||
from esphome.util import Registry
|
||||
|
||||
CODEOWNERS = ['@esphome/core']
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
DEVICE_CLASSES = [
|
||||
DEVICE_CLASS_EMPTY, DEVICE_CLASS_BATTERY, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_POWER, DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLTAGE
|
||||
DEVICE_CLASS_EMPTY,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
]
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -30,222 +71,302 @@ def validate_send_first_at(value):
|
||||
send_first_at = value.get(CONF_SEND_FIRST_AT)
|
||||
send_every = value[CONF_SEND_EVERY]
|
||||
if send_first_at is not None and send_first_at > send_every:
|
||||
raise cv.Invalid("send_first_at must be smaller than or equal to send_every! {} <= {}"
|
||||
"".format(send_first_at, send_every))
|
||||
raise cv.Invalid(
|
||||
"send_first_at must be smaller than or equal to send_every! {} <= {}"
|
||||
"".format(send_first_at, send_every)
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
FILTER_REGISTRY = Registry()
|
||||
validate_filters = cv.validate_registry('filter', FILTER_REGISTRY)
|
||||
validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
|
||||
|
||||
|
||||
def validate_datapoint(value):
|
||||
if isinstance(value, dict):
|
||||
return cv.Schema({
|
||||
cv.Required(CONF_FROM): cv.float_,
|
||||
cv.Required(CONF_TO): cv.float_,
|
||||
})(value)
|
||||
return cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_FROM): cv.float_,
|
||||
cv.Required(CONF_TO): cv.float_,
|
||||
}
|
||||
)(value)
|
||||
value = cv.string(value)
|
||||
if '->' not in value:
|
||||
if "->" not in value:
|
||||
raise cv.Invalid("Datapoint mapping must contain '->'")
|
||||
a, b = value.split('->', 1)
|
||||
a, b = value.split("->", 1)
|
||||
a, b = a.strip(), b.strip()
|
||||
return validate_datapoint({
|
||||
CONF_FROM: cv.float_(a),
|
||||
CONF_TO: cv.float_(b)
|
||||
})
|
||||
return validate_datapoint({CONF_FROM: cv.float_(a), CONF_TO: cv.float_(b)})
|
||||
|
||||
|
||||
# Base
|
||||
sensor_ns = cg.esphome_ns.namespace('sensor')
|
||||
Sensor = sensor_ns.class_('Sensor', cg.Nameable)
|
||||
SensorPtr = Sensor.operator('ptr')
|
||||
sensor_ns = cg.esphome_ns.namespace("sensor")
|
||||
Sensor = sensor_ns.class_("Sensor", cg.Nameable)
|
||||
SensorPtr = Sensor.operator("ptr")
|
||||
|
||||
# Triggers
|
||||
SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', automation.Trigger.template(cg.float_))
|
||||
SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger',
|
||||
automation.Trigger.template(cg.float_))
|
||||
ValueRangeTrigger = sensor_ns.class_('ValueRangeTrigger', automation.Trigger.template(cg.float_),
|
||||
cg.Component)
|
||||
SensorPublishAction = sensor_ns.class_('SensorPublishAction', automation.Action)
|
||||
SensorStateTrigger = sensor_ns.class_(
|
||||
"SensorStateTrigger", automation.Trigger.template(cg.float_)
|
||||
)
|
||||
SensorRawStateTrigger = sensor_ns.class_(
|
||||
"SensorRawStateTrigger", automation.Trigger.template(cg.float_)
|
||||
)
|
||||
ValueRangeTrigger = sensor_ns.class_(
|
||||
"ValueRangeTrigger", automation.Trigger.template(cg.float_), cg.Component
|
||||
)
|
||||
SensorPublishAction = sensor_ns.class_("SensorPublishAction", automation.Action)
|
||||
|
||||
# Filters
|
||||
Filter = sensor_ns.class_('Filter')
|
||||
MedianFilter = sensor_ns.class_('MedianFilter', Filter)
|
||||
MinFilter = sensor_ns.class_('MinFilter', Filter)
|
||||
MaxFilter = sensor_ns.class_('MaxFilter', Filter)
|
||||
SlidingWindowMovingAverageFilter = sensor_ns.class_('SlidingWindowMovingAverageFilter', Filter)
|
||||
ExponentialMovingAverageFilter = sensor_ns.class_('ExponentialMovingAverageFilter', Filter)
|
||||
LambdaFilter = sensor_ns.class_('LambdaFilter', Filter)
|
||||
OffsetFilter = sensor_ns.class_('OffsetFilter', Filter)
|
||||
MultiplyFilter = sensor_ns.class_('MultiplyFilter', Filter)
|
||||
FilterOutValueFilter = sensor_ns.class_('FilterOutValueFilter', Filter)
|
||||
ThrottleFilter = sensor_ns.class_('ThrottleFilter', Filter)
|
||||
DebounceFilter = sensor_ns.class_('DebounceFilter', Filter, cg.Component)
|
||||
HeartbeatFilter = sensor_ns.class_('HeartbeatFilter', Filter, cg.Component)
|
||||
DeltaFilter = sensor_ns.class_('DeltaFilter', Filter)
|
||||
OrFilter = sensor_ns.class_('OrFilter', Filter)
|
||||
CalibrateLinearFilter = sensor_ns.class_('CalibrateLinearFilter', Filter)
|
||||
CalibratePolynomialFilter = sensor_ns.class_('CalibratePolynomialFilter', Filter)
|
||||
SensorInRangeCondition = sensor_ns.class_('SensorInRangeCondition', Filter)
|
||||
Filter = sensor_ns.class_("Filter")
|
||||
MedianFilter = sensor_ns.class_("MedianFilter", Filter)
|
||||
MinFilter = sensor_ns.class_("MinFilter", Filter)
|
||||
MaxFilter = sensor_ns.class_("MaxFilter", Filter)
|
||||
SlidingWindowMovingAverageFilter = sensor_ns.class_(
|
||||
"SlidingWindowMovingAverageFilter", Filter
|
||||
)
|
||||
ExponentialMovingAverageFilter = sensor_ns.class_(
|
||||
"ExponentialMovingAverageFilter", Filter
|
||||
)
|
||||
LambdaFilter = sensor_ns.class_("LambdaFilter", Filter)
|
||||
OffsetFilter = sensor_ns.class_("OffsetFilter", Filter)
|
||||
MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter)
|
||||
FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter)
|
||||
ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter)
|
||||
DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component)
|
||||
HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component)
|
||||
DeltaFilter = sensor_ns.class_("DeltaFilter", Filter)
|
||||
OrFilter = sensor_ns.class_("OrFilter", Filter)
|
||||
CalibrateLinearFilter = sensor_ns.class_("CalibrateLinearFilter", Filter)
|
||||
CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter)
|
||||
SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter)
|
||||
|
||||
unit_of_measurement = cv.string_strict
|
||||
accuracy_decimals = cv.int_
|
||||
icon = cv.icon
|
||||
device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space='_')
|
||||
device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
||||
|
||||
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
|
||||
cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTSensorComponent),
|
||||
cv.GenerateID(): cv.declare_id(Sensor),
|
||||
cv.Optional(CONF_UNIT_OF_MEASUREMENT): unit_of_measurement,
|
||||
cv.Optional(CONF_ICON): icon,
|
||||
cv.Optional(CONF_ACCURACY_DECIMALS): accuracy_decimals,
|
||||
cv.Optional(CONF_DEVICE_CLASS): device_class,
|
||||
cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_EXPIRE_AFTER): cv.All(cv.requires_component('mqtt'),
|
||||
cv.Any(None, cv.positive_time_period_milliseconds)),
|
||||
cv.Optional(CONF_FILTERS): validate_filters,
|
||||
cv.Optional(CONF_ON_VALUE): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorStateTrigger),
|
||||
}),
|
||||
cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorRawStateTrigger),
|
||||
}),
|
||||
cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger),
|
||||
cv.Optional(CONF_ABOVE): cv.float_,
|
||||
cv.Optional(CONF_BELOW): cv.float_,
|
||||
}, cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
|
||||
})
|
||||
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend(
|
||||
{
|
||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSensorComponent),
|
||||
cv.GenerateID(): cv.declare_id(Sensor),
|
||||
cv.Optional(CONF_UNIT_OF_MEASUREMENT): unit_of_measurement,
|
||||
cv.Optional(CONF_ICON): icon,
|
||||
cv.Optional(CONF_ACCURACY_DECIMALS): accuracy_decimals,
|
||||
cv.Optional(CONF_DEVICE_CLASS): device_class,
|
||||
cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_EXPIRE_AFTER): cv.All(
|
||||
cv.requires_component("mqtt"),
|
||||
cv.Any(None, cv.positive_time_period_milliseconds),
|
||||
),
|
||||
cv.Optional(CONF_FILTERS): validate_filters,
|
||||
cv.Optional(CONF_ON_VALUE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorStateTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorRawStateTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger),
|
||||
cv.Optional(CONF_ABOVE): cv.float_,
|
||||
cv.Optional(CONF_BELOW): cv.float_,
|
||||
},
|
||||
cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW),
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def sensor_schema(unit_of_measurement_, icon_, accuracy_decimals_, device_class_):
|
||||
# type: (str, str, int, str) -> cv.Schema
|
||||
schema = SENSOR_SCHEMA
|
||||
if unit_of_measurement_ != UNIT_EMPTY:
|
||||
schema = schema.extend({
|
||||
cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=unit_of_measurement_): unit_of_measurement
|
||||
})
|
||||
schema = schema.extend(
|
||||
{
|
||||
cv.Optional(
|
||||
CONF_UNIT_OF_MEASUREMENT, default=unit_of_measurement_
|
||||
): unit_of_measurement
|
||||
}
|
||||
)
|
||||
if icon_ != ICON_EMPTY:
|
||||
schema = schema.extend({cv.Optional(CONF_ICON, default=icon_): icon})
|
||||
if accuracy_decimals_ != 0:
|
||||
schema = schema.extend({
|
||||
cv.Optional(CONF_ACCURACY_DECIMALS, default=accuracy_decimals_): accuracy_decimals,
|
||||
})
|
||||
schema = schema.extend(
|
||||
{
|
||||
cv.Optional(
|
||||
CONF_ACCURACY_DECIMALS, default=accuracy_decimals_
|
||||
): accuracy_decimals,
|
||||
}
|
||||
)
|
||||
if device_class_ != DEVICE_CLASS_EMPTY:
|
||||
schema = schema.extend({
|
||||
cv.Optional(CONF_DEVICE_CLASS, default=device_class_): device_class
|
||||
})
|
||||
schema = schema.extend(
|
||||
{cv.Optional(CONF_DEVICE_CLASS, default=device_class_): device_class}
|
||||
)
|
||||
return schema
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('offset', OffsetFilter, cv.float_)
|
||||
@FILTER_REGISTRY.register("offset", OffsetFilter, cv.float_)
|
||||
def offset_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('multiply', MultiplyFilter, cv.float_)
|
||||
@FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.float_)
|
||||
def multiply_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('filter_out', FilterOutValueFilter, cv.float_)
|
||||
@FILTER_REGISTRY.register("filter_out", FilterOutValueFilter, cv.float_)
|
||||
def filter_out_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config)
|
||||
|
||||
|
||||
MEDIAN_SCHEMA = cv.All(cv.Schema({
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}), validate_send_first_at)
|
||||
MEDIAN_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}
|
||||
),
|
||||
validate_send_first_at,
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('median', MedianFilter, MEDIAN_SCHEMA)
|
||||
@FILTER_REGISTRY.register("median", MedianFilter, MEDIAN_SCHEMA)
|
||||
def median_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT])
|
||||
yield cg.new_Pvariable(
|
||||
filter_id,
|
||||
config[CONF_WINDOW_SIZE],
|
||||
config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT],
|
||||
)
|
||||
|
||||
|
||||
MIN_SCHEMA = cv.All(cv.Schema({
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}), validate_send_first_at)
|
||||
MIN_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}
|
||||
),
|
||||
validate_send_first_at,
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('min', MinFilter, MIN_SCHEMA)
|
||||
@FILTER_REGISTRY.register("min", MinFilter, MIN_SCHEMA)
|
||||
def min_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT])
|
||||
yield cg.new_Pvariable(
|
||||
filter_id,
|
||||
config[CONF_WINDOW_SIZE],
|
||||
config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT],
|
||||
)
|
||||
|
||||
|
||||
MAX_SCHEMA = cv.All(cv.Schema({
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}), validate_send_first_at)
|
||||
MAX_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=5): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}
|
||||
),
|
||||
validate_send_first_at,
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('max', MaxFilter, MAX_SCHEMA)
|
||||
@FILTER_REGISTRY.register("max", MaxFilter, MAX_SCHEMA)
|
||||
def max_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT])
|
||||
yield cg.new_Pvariable(
|
||||
filter_id,
|
||||
config[CONF_WINDOW_SIZE],
|
||||
config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT],
|
||||
)
|
||||
|
||||
|
||||
SLIDING_AVERAGE_SCHEMA = cv.All(cv.Schema({
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=15): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}), validate_send_first_at)
|
||||
SLIDING_AVERAGE_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_WINDOW_SIZE, default=15): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
|
||||
}
|
||||
),
|
||||
validate_send_first_at,
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('sliding_window_moving_average', SlidingWindowMovingAverageFilter,
|
||||
SLIDING_AVERAGE_SCHEMA)
|
||||
@FILTER_REGISTRY.register(
|
||||
"sliding_window_moving_average",
|
||||
SlidingWindowMovingAverageFilter,
|
||||
SLIDING_AVERAGE_SCHEMA,
|
||||
)
|
||||
def sliding_window_moving_average_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT])
|
||||
yield cg.new_Pvariable(
|
||||
filter_id,
|
||||
config[CONF_WINDOW_SIZE],
|
||||
config[CONF_SEND_EVERY],
|
||||
config[CONF_SEND_FIRST_AT],
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('exponential_moving_average', ExponentialMovingAverageFilter, cv.Schema({
|
||||
cv.Optional(CONF_ALPHA, default=0.1): cv.positive_float,
|
||||
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||
}))
|
||||
@FILTER_REGISTRY.register(
|
||||
"exponential_moving_average",
|
||||
ExponentialMovingAverageFilter,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_ALPHA, default=0.1): cv.positive_float,
|
||||
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||
}
|
||||
),
|
||||
)
|
||||
def exponential_moving_average_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY])
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.returning_lambda)
|
||||
@FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda)
|
||||
def lambda_filter_to_code(config, filter_id):
|
||||
lambda_ = yield cg.process_lambda(config, [(float, 'x')],
|
||||
return_type=cg.optional.template(float))
|
||||
lambda_ = yield cg.process_lambda(
|
||||
config, [(float, "x")], return_type=cg.optional.template(float)
|
||||
)
|
||||
yield cg.new_Pvariable(filter_id, lambda_)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('delta', DeltaFilter, cv.float_)
|
||||
@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_)
|
||||
def delta_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('or', OrFilter, validate_filters)
|
||||
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
|
||||
def or_filter_to_code(config, filter_id):
|
||||
filters = yield build_filters(config)
|
||||
yield cg.new_Pvariable(filter_id, filters)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('throttle', ThrottleFilter, cv.positive_time_period_milliseconds)
|
||||
@FILTER_REGISTRY.register(
|
||||
"throttle", ThrottleFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def throttle_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, config)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('heartbeat', HeartbeatFilter, cv.positive_time_period_milliseconds)
|
||||
@FILTER_REGISTRY.register(
|
||||
"heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def heartbeat_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id, config)
|
||||
yield cg.register_component(var, {})
|
||||
yield var
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('debounce', DebounceFilter, cv.positive_time_period_milliseconds)
|
||||
@FILTER_REGISTRY.register(
|
||||
"debounce", DebounceFilter, cv.positive_time_period_milliseconds
|
||||
)
|
||||
def debounce_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id, config)
|
||||
yield cg.register_component(var, {})
|
||||
@@ -254,13 +375,20 @@ def debounce_filter_to_code(config, filter_id):
|
||||
|
||||
def validate_not_all_from_same(config):
|
||||
if all(conf[CONF_FROM] == config[0][CONF_FROM] for conf in config):
|
||||
raise cv.Invalid("The 'from' values of the calibrate_linear filter cannot all point "
|
||||
"to the same value! Please add more values to the filter.")
|
||||
raise cv.Invalid(
|
||||
"The 'from' values of the calibrate_linear filter cannot all point "
|
||||
"to the same value! Please add more values to the filter."
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('calibrate_linear', CalibrateLinearFilter, cv.All(
|
||||
cv.ensure_list(validate_datapoint), cv.Length(min=2), validate_not_all_from_same))
|
||||
@FILTER_REGISTRY.register(
|
||||
"calibrate_linear",
|
||||
CalibrateLinearFilter,
|
||||
cv.All(
|
||||
cv.ensure_list(validate_datapoint), cv.Length(min=2), validate_not_all_from_same
|
||||
),
|
||||
)
|
||||
def calibrate_linear_filter_to_code(config, filter_id):
|
||||
x = [conf[CONF_FROM] for conf in config]
|
||||
y = [conf[CONF_TO] for conf in config]
|
||||
@@ -268,26 +396,40 @@ def calibrate_linear_filter_to_code(config, filter_id):
|
||||
yield cg.new_Pvariable(filter_id, k, b)
|
||||
|
||||
|
||||
CONF_DATAPOINTS = 'datapoints'
|
||||
CONF_DEGREE = 'degree'
|
||||
CONF_DATAPOINTS = "datapoints"
|
||||
CONF_DEGREE = "degree"
|
||||
|
||||
|
||||
def validate_calibrate_polynomial(config):
|
||||
if config[CONF_DEGREE] >= len(config[CONF_DATAPOINTS]):
|
||||
raise cv.Invalid("Degree is too high! Maximum possible degree with given datapoints is "
|
||||
"{}".format(len(config[CONF_DATAPOINTS]) - 1), [CONF_DEGREE])
|
||||
raise cv.Invalid(
|
||||
"Degree is too high! Maximum possible degree with given datapoints is "
|
||||
"{}".format(len(config[CONF_DATAPOINTS]) - 1),
|
||||
[CONF_DEGREE],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register('calibrate_polynomial', CalibratePolynomialFilter, cv.All(cv.Schema({
|
||||
cv.Required(CONF_DATAPOINTS): cv.All(cv.ensure_list(validate_datapoint), cv.Length(min=1)),
|
||||
cv.Required(CONF_DEGREE): cv.positive_int,
|
||||
}), validate_calibrate_polynomial))
|
||||
@FILTER_REGISTRY.register(
|
||||
"calibrate_polynomial",
|
||||
CalibratePolynomialFilter,
|
||||
cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_DATAPOINTS): cv.All(
|
||||
cv.ensure_list(validate_datapoint), cv.Length(min=1)
|
||||
),
|
||||
cv.Required(CONF_DEGREE): cv.positive_int,
|
||||
}
|
||||
),
|
||||
validate_calibrate_polynomial,
|
||||
),
|
||||
)
|
||||
def calibrate_polynomial_filter_to_code(config, filter_id):
|
||||
x = [conf[CONF_FROM] for conf in config[CONF_DATAPOINTS]]
|
||||
y = [conf[CONF_TO] for conf in config[CONF_DATAPOINTS]]
|
||||
degree = config[CONF_DEGREE]
|
||||
a = [[1] + [x_**(i+1) for i in range(degree)] for x_ in x]
|
||||
a = [[1] + [x_ ** (i + 1) for i in range(degree)] for x_ in x]
|
||||
# Column vector
|
||||
b = [[v] for v in y]
|
||||
res = [v[0] for v in _lstsq(a, b)]
|
||||
@@ -319,20 +461,20 @@ def setup_sensor_core_(var, config):
|
||||
|
||||
for conf in config.get(CONF_ON_VALUE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [(float, 'x')], conf)
|
||||
yield automation.build_automation(trigger, [(float, "x")], conf)
|
||||
for conf in config.get(CONF_ON_RAW_VALUE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [(float, 'x')], conf)
|
||||
yield automation.build_automation(trigger, [(float, "x")], conf)
|
||||
for conf in config.get(CONF_ON_VALUE_RANGE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield cg.register_component(trigger, conf)
|
||||
if CONF_ABOVE in conf:
|
||||
template_ = yield cg.templatable(conf[CONF_ABOVE], [(float, 'x')], float)
|
||||
template_ = yield cg.templatable(conf[CONF_ABOVE], [(float, "x")], float)
|
||||
cg.add(trigger.set_min(template_))
|
||||
if CONF_BELOW in conf:
|
||||
template_ = yield cg.templatable(conf[CONF_BELOW], [(float, 'x')], float)
|
||||
template_ = yield cg.templatable(conf[CONF_BELOW], [(float, "x")], float)
|
||||
cg.add(trigger.set_max(template_))
|
||||
yield automation.build_automation(trigger, [(float, 'x')], conf)
|
||||
yield automation.build_automation(trigger, [(float, "x")], conf)
|
||||
|
||||
if CONF_MQTT_ID in config:
|
||||
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
|
||||
@@ -360,15 +502,19 @@ def new_sensor(config):
|
||||
yield var
|
||||
|
||||
|
||||
SENSOR_IN_RANGE_CONDITION_SCHEMA = cv.All({
|
||||
cv.Required(CONF_ID): cv.use_id(Sensor),
|
||||
cv.Optional(CONF_ABOVE): cv.float_,
|
||||
cv.Optional(CONF_BELOW): cv.float_,
|
||||
}, cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))
|
||||
SENSOR_IN_RANGE_CONDITION_SCHEMA = cv.All(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(Sensor),
|
||||
cv.Optional(CONF_ABOVE): cv.float_,
|
||||
cv.Optional(CONF_BELOW): cv.float_,
|
||||
},
|
||||
cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW),
|
||||
)
|
||||
|
||||
|
||||
@automation.register_condition('sensor.in_range', SensorInRangeCondition,
|
||||
SENSOR_IN_RANGE_CONDITION_SCHEMA)
|
||||
@automation.register_condition(
|
||||
"sensor.in_range", SensorInRangeCondition, SENSOR_IN_RANGE_CONDITION_SCHEMA
|
||||
)
|
||||
def sensor_in_range_to_code(config, condition_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(condition_id, template_arg, paren)
|
||||
@@ -420,7 +566,7 @@ def _mat_identity(n):
|
||||
|
||||
def _mat_dot(a, b):
|
||||
b_t = _mat_transpose(b)
|
||||
return [[sum(x*y for x, y in zip(row_a, col_b)) for col_b in b_t] for row_a in a]
|
||||
return [[sum(x * y for x, y in zip(row_a, col_b)) for col_b in b_t] for row_a in a]
|
||||
|
||||
|
||||
def _mat_inverse(m):
|
||||
@@ -431,7 +577,7 @@ def _mat_inverse(m):
|
||||
for diag in range(n):
|
||||
# If diag element is 0, swap rows
|
||||
if m[diag][diag] == 0:
|
||||
for i in range(diag+1, n):
|
||||
for i in range(diag + 1, n):
|
||||
if m[i][diag] != 0:
|
||||
break
|
||||
else:
|
||||
@@ -468,5 +614,5 @@ def _lstsq(a, b):
|
||||
|
||||
@coroutine_with_priority(40.0)
|
||||
def to_code(config):
|
||||
cg.add_define('USE_SENSOR')
|
||||
cg.add_define("USE_SENSOR")
|
||||
cg.add_global(sensor_ns.using)
|
||||
|
Reference in New Issue
Block a user