mirror of
https://github.com/esphome/esphome.git
synced 2024-11-30 18:54:14 +01:00
Queue size sensor (#15)
* added automatic queue size sensor * queue size sensor as regular sensor component
This commit is contained in:
parent
e4628689b2
commit
3188efcf62
10 changed files with 149 additions and 120 deletions
|
@ -3,18 +3,21 @@ from esphome import pins
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_BYTES,
|
||||
CONF_DIV_RATIO,
|
||||
CONF_ID,
|
||||
CONF_LOGGER,
|
||||
CONF_PROTOCOL,
|
||||
CONF_RX_PIN,
|
||||
CONF_TX_PIN,
|
||||
CONF_TYPE,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
|
||||
CODEOWNERS = ["@j0ta29"]
|
||||
DEPENDENCIES = []
|
||||
DEPENDENCIES = ["sensor"]
|
||||
AUTO_LOAD = []
|
||||
MULTI_CONF = False
|
||||
|
||||
|
@ -32,6 +35,73 @@ DAY_OF_WEEK = {
|
|||
}
|
||||
CONF_DAY_OF_WEEK = "day_of_week"
|
||||
|
||||
|
||||
def check_address_for_types(types_address_needed):
|
||||
def validator_(config):
|
||||
address_needed = config[CONF_TYPE] in types_address_needed
|
||||
address_defined = CONF_ADDRESS in config
|
||||
if address_needed and not address_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ADDRESS} is required for this types: {types_address_needed}"
|
||||
)
|
||||
if not address_needed and address_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ADDRESS} is only allowed for this types: {types_address_needed}"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_bytes_for_types(types_bytes_needed):
|
||||
def validator_(config):
|
||||
bytes_needed = config[CONF_TYPE] in types_bytes_needed
|
||||
bytes_defined = CONF_BYTES in config
|
||||
if bytes_needed and not bytes_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} is required for this types: {types_bytes_needed}"
|
||||
)
|
||||
if not bytes_needed and bytes_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} is only allowed for this types: {types_bytes_needed}"
|
||||
)
|
||||
|
||||
types_bytes_range_1_to_9 = ["MAP", "RAW"]
|
||||
if config[CONF_TYPE] in types_bytes_range_1_to_9 and config[
|
||||
CONF_BYTES
|
||||
] not in range(0, 10):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} must be between 1 and 9 for this types: {types_bytes_range_1_to_9}"
|
||||
)
|
||||
|
||||
types_bytes_day_schedule = ["DAY_SCHEDULE"]
|
||||
if config[CONF_TYPE] in types_bytes_day_schedule and config[CONF_BYTES] not in [
|
||||
56
|
||||
]:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} must be 56 for this types: {types_bytes_day_schedule}"
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_dow_for_types(types_dow_needed):
|
||||
def validator_(config):
|
||||
if config[CONF_TYPE] in types_dow_needed and CONF_DAY_OF_WEEK not in config:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_DAY_OF_WEEK} is required for this types: {types_dow_needed}"
|
||||
)
|
||||
if config[CONF_TYPE] not in types_dow_needed and CONF_DAY_OF_WEEK in config:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_DAY_OF_WEEK} is only allowed for this types: {types_dow_needed}"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
OptolinkComponent = optolink_ns.class_("Optolink", cg.Component)
|
||||
SENSOR_BASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
|
|
|
@ -258,6 +258,8 @@ void DatapointComponent::set_optolink_state_(const char *format, ...) {
|
|||
|
||||
std::string DatapointComponent::get_optolink_state_() { return optolink_->get_state(); }
|
||||
|
||||
int DatapointComponent::get_optolink_queue_size_() { return optolink_->get_queue_size(); };
|
||||
|
||||
void conv2_100_F::encode(uint8_t *out, DPValue in) {
|
||||
int16_t tmp = floor((in.getFloat() * 100) + 0.5);
|
||||
out[1] = tmp >> 8;
|
||||
|
|
|
@ -48,6 +48,7 @@ class DatapointComponent {
|
|||
void unfitting_value_type_();
|
||||
void set_optolink_state_(const char *format, ...);
|
||||
std::string get_optolink_state_();
|
||||
int get_optolink_queue_size_();
|
||||
|
||||
private:
|
||||
const size_t max_retries_until_reset_ = 10;
|
||||
|
|
|
@ -32,10 +32,9 @@ void Optolink::setup() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void Optolink::loop() {
|
||||
// ESP_LOGD(TAG, "queue size: %d", VitoWiFi.queueSize());
|
||||
VitoWiFi.loop();
|
||||
}
|
||||
void Optolink::loop() { VitoWiFi.loop(); }
|
||||
|
||||
int Optolink::get_queue_size() { return VitoWiFi.queueSize(); }
|
||||
|
||||
void Optolink::set_state(const char *format, ...) {
|
||||
va_list args;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#ifdef USE_ARDUINO
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "VitoWiFi.h"
|
||||
|
||||
namespace esphome {
|
||||
|
@ -34,6 +35,8 @@ class Optolink : public esphome::Component, public Print {
|
|||
|
||||
void set_state(const char *format, ...);
|
||||
std::string get_state() { return state_; }
|
||||
|
||||
int get_queue_size();
|
||||
};
|
||||
|
||||
} // namespace optolink
|
||||
|
|
|
@ -7,27 +7,42 @@ from esphome.const import (
|
|||
CONF_DIV_RATIO,
|
||||
CONF_ID,
|
||||
CONF_MIN_VALUE,
|
||||
CONF_TYPE,
|
||||
)
|
||||
from .. import (
|
||||
CONF_OPTOLINK_ID,
|
||||
SENSOR_BASE_SCHEMA,
|
||||
check_address_for_types,
|
||||
check_bytes_for_types,
|
||||
optolink_ns,
|
||||
)
|
||||
from .. import CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA, optolink_ns
|
||||
|
||||
DEPENDENCIES = ["optolink"]
|
||||
CODEOWNERS = ["@j0ta29"]
|
||||
|
||||
SensorType = optolink_ns.enum("SensorType")
|
||||
TYPE = {
|
||||
"DATAPOINT": SensorType.SENSOR_TYPE_DATAPOINT,
|
||||
"QUEUE_SIZE": SensorType.SENSOR_TYPE_QUEUE_SIZE,
|
||||
}
|
||||
|
||||
OptolinkSensor = optolink_ns.class_(
|
||||
"OptolinkSensor", sensor.Sensor, cg.PollingComponent
|
||||
)
|
||||
CONFIG_SCHEMA = (
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.SENSOR_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(OptolinkSensor),
|
||||
cv.Required(CONF_ADDRESS): cv.hex_uint32_t,
|
||||
cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True),
|
||||
cv.Optional(CONF_TYPE, default="DATAPOINT"): cv.enum(TYPE, upper=True),
|
||||
cv.Optional(CONF_ADDRESS): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_BYTES): cv.one_of(1, 2, 4, int=True),
|
||||
cv.Optional(CONF_MIN_VALUE): cv.float_,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(SENSOR_BASE_SCHEMA)
|
||||
.extend(SENSOR_BASE_SCHEMA),
|
||||
check_address_for_types(["DATAPOINT"]),
|
||||
check_bytes_for_types(["DATAPOINT"]),
|
||||
)
|
||||
|
||||
|
||||
|
@ -38,8 +53,12 @@ async def to_code(config):
|
|||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||
cg.add(var.set_bytes(config[CONF_BYTES]))
|
||||
cg.add(var.set_div_ratio(config[CONF_DIV_RATIO]))
|
||||
cg.add(var.set_type(config[CONF_TYPE]))
|
||||
if CONF_ADDRESS in config:
|
||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||
if CONF_BYTES in config:
|
||||
cg.add(var.set_bytes(config[CONF_BYTES]))
|
||||
if CONF_DIV_RATIO in config:
|
||||
cg.add(var.set_div_ratio(config[CONF_DIV_RATIO]))
|
||||
if CONF_MIN_VALUE in config:
|
||||
cg.add(var.set_min_value(config[CONF_MIN_VALUE]))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifdef USE_ARDUINO
|
||||
|
||||
#include "optolink_sensor.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "../optolink.h"
|
||||
|
||||
namespace esphome {
|
||||
|
@ -8,7 +9,26 @@ namespace optolink {
|
|||
|
||||
static const char *const TAG = "optolink.sensor";
|
||||
|
||||
void OptolinkSensor::set_min_value(float min_value) { min_value_ = -29.3; }
|
||||
void OptolinkSensor::setup() {
|
||||
switch (type_) {
|
||||
case SENSOR_TYPE_DATAPOINT:
|
||||
setup_datapoint_();
|
||||
break;
|
||||
case SENSOR_TYPE_QUEUE_SIZE:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void OptolinkSensor::update() {
|
||||
switch (type_) {
|
||||
case SENSOR_TYPE_DATAPOINT:
|
||||
datapoint_read_request_();
|
||||
break;
|
||||
case SENSOR_TYPE_QUEUE_SIZE:
|
||||
publish_state(get_optolink_queue_size_());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTBEGIN
|
||||
void OptolinkSensor::datapoint_value_changed(uint8_t value) {
|
||||
|
|
|
@ -10,17 +10,20 @@
|
|||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
enum SensorType { SENSOR_TYPE_DATAPOINT, SENSOR_TYPE_QUEUE_SIZE };
|
||||
|
||||
class OptolinkSensor : public DatapointComponent, public esphome::sensor::Sensor, public esphome::PollingComponent {
|
||||
public:
|
||||
OptolinkSensor(Optolink *optolink) : DatapointComponent(optolink) {
|
||||
set_state_class(esphome::sensor::STATE_CLASS_MEASUREMENT);
|
||||
}
|
||||
|
||||
void set_min_value(float min_value);
|
||||
void set_type(SensorType type) { type_ = type; }
|
||||
void set_min_value(float min_value) { min_value_ = min_value; }
|
||||
|
||||
protected:
|
||||
void setup() override { setup_datapoint_(); }
|
||||
void update() override { datapoint_read_request_(); }
|
||||
void setup() override;
|
||||
void update() override;
|
||||
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void datapoint_value_changed(float value) override { publish_state(value); };
|
||||
|
@ -29,6 +32,7 @@ class OptolinkSensor : public DatapointComponent, public esphome::sensor::Sensor
|
|||
void datapoint_value_changed(uint32_t value) override;
|
||||
|
||||
private:
|
||||
SensorType type_ = SENSOR_TYPE_DATAPOINT;
|
||||
float min_value_ = -FLT_MAX;
|
||||
};
|
||||
} // namespace optolink
|
||||
|
|
|
@ -12,6 +12,9 @@ from esphome.const import (
|
|||
from .. import (
|
||||
CONF_DAY_OF_WEEK,
|
||||
DAY_OF_WEEK,
|
||||
check_address_for_types,
|
||||
check_bytes_for_types,
|
||||
check_dow_for_types,
|
||||
optolink_ns,
|
||||
CONF_OPTOLINK_ID,
|
||||
SENSOR_BASE_SCHEMA,
|
||||
|
@ -25,7 +28,6 @@ TYPE = {
|
|||
"MAP": TextSensorType.TEXT_SENSOR_TYPE_MAP,
|
||||
"RAW": TextSensorType.TEXT_SENSOR_TYPE_RAW,
|
||||
"DAY_SCHEDULE": TextSensorType.TEXT_SENSOR_TYPE_DAY_SCHEDULE,
|
||||
"DAY_SCHEDULE_SYNCHRONIZED": TextSensorType.TEXT_SENSOR_TYPE_DAY_SCHEDULE_SYNCHRONIZED,
|
||||
"DEVICE_INFO": TextSensorType.TEXT_SENSOR_TYPE_DEVICE_INFO,
|
||||
"STATE_INFO": TextSensorType.TEXT_SENSOR_TYPE_STATE_INFO,
|
||||
}
|
||||
|
@ -34,103 +36,6 @@ OptolinkTextSensor = optolink_ns.class_(
|
|||
"OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent
|
||||
)
|
||||
|
||||
|
||||
def check_address():
|
||||
def validator_(config):
|
||||
types_address_needed = [
|
||||
"MAP",
|
||||
"RAW",
|
||||
"DAY_SCHEDULE",
|
||||
"DAY_SCHEDULE_SYNCHRONIZED",
|
||||
]
|
||||
address_needed = config[CONF_TYPE] in types_address_needed
|
||||
address_defined = CONF_ADDRESS in config
|
||||
if address_needed and not address_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ADDRESS} is required for this types: {types_address_needed}"
|
||||
)
|
||||
if not address_needed and address_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ADDRESS} is only allowed for this types: {types_address_needed}"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_bytes():
|
||||
def validator_(config):
|
||||
types_bytes_needed = ["MAP", "RAW", "DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
bytes_needed = config[CONF_TYPE] in types_bytes_needed
|
||||
bytes_defined = CONF_BYTES in config
|
||||
if bytes_needed and not bytes_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} is required for this types: {types_bytes_needed}"
|
||||
)
|
||||
if not bytes_needed and bytes_defined:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} is only allowed for this types: {types_bytes_needed}"
|
||||
)
|
||||
|
||||
types_bytes_range_1_to_9 = ["MAP", "RAW"]
|
||||
if config[CONF_TYPE] in types_bytes_range_1_to_9 and config[
|
||||
CONF_BYTES
|
||||
] not in range(0, 10):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} must be between 1 and 9 for this types: {types_bytes_range_1_to_9}"
|
||||
)
|
||||
|
||||
types_bytes_day_schedule = ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
if config[CONF_TYPE] in types_bytes_day_schedule and config[CONF_BYTES] not in [
|
||||
56
|
||||
]:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} must be 56 for this types: {types_bytes_day_schedule}"
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_dow():
|
||||
def validator_(config):
|
||||
types_dow_needed = ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
if config[CONF_TYPE] in types_dow_needed and CONF_DAY_OF_WEEK not in config:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_DAY_OF_WEEK} is required for this types: {types_dow_needed}"
|
||||
)
|
||||
if config[CONF_TYPE] not in types_dow_needed and CONF_DAY_OF_WEEK in config:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_DAY_OF_WEEK} is only allowed for this types: {types_dow_needed}"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_entity_id():
|
||||
def validator_(config):
|
||||
types_entitiy_id_needed = ["DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
if (
|
||||
config[CONF_TYPE] in types_entitiy_id_needed
|
||||
and CONF_ENTITY_ID not in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ENTITY_ID} is required for this types: {types_entitiy_id_needed}"
|
||||
)
|
||||
if (
|
||||
config[CONF_TYPE] not in types_entitiy_id_needed
|
||||
and CONF_ENTITY_ID in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ENTITY_ID} is only allowed for this types: {types_entitiy_id_needed}"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
text_sensor.TEXT_SENSOR_SCHEMA.extend(
|
||||
{
|
||||
|
@ -144,10 +49,9 @@ CONFIG_SCHEMA = cv.All(
|
|||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(SENSOR_BASE_SCHEMA),
|
||||
check_address(),
|
||||
check_bytes(),
|
||||
check_dow(),
|
||||
check_entity_id(),
|
||||
check_address_for_types(["MAP", "RAW", "DAY_SCHEDULE"]),
|
||||
check_bytes_for_types(["MAP", "RAW", "DAY_SCHEDULE"]),
|
||||
check_dow_for_types(["DAY_SCHEDULE"]),
|
||||
)
|
||||
|
||||
|
||||
|
@ -161,7 +65,8 @@ async def to_code(config):
|
|||
cg.add(var.set_type(config[CONF_TYPE]))
|
||||
if CONF_ADDRESS in config:
|
||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||
cg.add(var.set_div_ratio(config[CONF_DIV_RATIO]))
|
||||
if CONF_DIV_RATIO in config:
|
||||
cg.add(var.set_div_ratio(config[CONF_DIV_RATIO]))
|
||||
if CONF_BYTES in config:
|
||||
cg.add(var.set_bytes(config[CONF_BYTES]))
|
||||
if CONF_DAY_OF_WEEK in config:
|
||||
|
|
|
@ -13,6 +13,12 @@ sensor:
|
|||
icon: mdi:thermometer-chevron-down
|
||||
device_class: temperature
|
||||
update_interval: 120s
|
||||
- platform: optolink
|
||||
type: QUEUE_SIZE
|
||||
name: Optolink Queue Size
|
||||
icon: mdi:queue-first-in-last-out
|
||||
entity_category: diagnostic
|
||||
update_interval: 1s
|
||||
|
||||
text_sensor:
|
||||
- platform: optolink
|
||||
|
|
Loading…
Reference in a new issue