mirror of
https://github.com/esphome/esphome.git
synced 2025-02-17 16:53:13 +01:00
first working rework for text_sendor mode DAY_SCHEDULE_SYNCHRONIZED
This commit is contained in:
parent
878e7c93a3
commit
f0ba8873ca
16 changed files with 429 additions and 203 deletions
|
@ -34,7 +34,6 @@ DeviceInfoSensor = optolink_ns.class_(
|
|||
"OptolinkDeviceInfoSensor", ts.TextSensor, cg.PollingComponent
|
||||
)
|
||||
DEVICE_INFO_SENSOR_ID = "device_info_sensor_id"
|
||||
|
||||
CONF_OPTOLINK_ID = "optolink_id"
|
||||
SENSOR_BASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
|
|
|
@ -20,11 +20,11 @@ class OptolinkBinarySensor : public OptolinkSensorBase,
|
|||
}
|
||||
|
||||
protected:
|
||||
void setup() override { setup_datapoint_(); }
|
||||
void setup() override { setup_datapoint(); }
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(state); };
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(uint8_t state) override { publish_state(state); };
|
||||
};
|
||||
} // namespace optolink
|
||||
} // namespace esphome
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace optolink {
|
|||
|
||||
void OptolinkNumber::control(float value) {
|
||||
if (value > traits.get_max_value() || value < traits.get_min_value()) {
|
||||
optolink_->set_error("datapoint value of number %s not in allowed range", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkNumber", "datapoint value of number %s not in allowed range", get_sensor_name().c_str());
|
||||
optolink_->set_error("datapoint value of number %s not in allowed range", get_component_name().c_str());
|
||||
ESP_LOGE("OptolinkNumber", "datapoint value of number %s not in allowed range", get_component_name().c_str());
|
||||
} else {
|
||||
ESP_LOGI("OptolinkNumber", "control of number %s to value %f", get_sensor_name().c_str(), value);
|
||||
update_datapoint_(value);
|
||||
ESP_LOGI("OptolinkNumber", "control of number %s to value %f", get_component_name().c_str(), value);
|
||||
update_datapoint(value);
|
||||
publish_state(value);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,11 +15,14 @@ class OptolinkNumber : public OptolinkSensorBase, public esphome::number::Number
|
|||
OptolinkNumber(Optolink *optolink) : OptolinkSensorBase(optolink, true) {}
|
||||
|
||||
protected:
|
||||
void setup() override { setup_datapoint_(); }
|
||||
void setup() override { setup_datapoint(); }
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(state); };
|
||||
void value_changed(uint8_t state) override { publish_state(state); };
|
||||
void value_changed(uint16_t state) override { publish_state(state); };
|
||||
void value_changed(uint32_t state) override { publish_state(state); };
|
||||
|
||||
void control(float value) override;
|
||||
};
|
||||
|
|
|
@ -15,10 +15,12 @@ VitoWiFiClass<P300> VitoWiFi; // this is not really a fallback but dedicated to
|
|||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
static const char *const TAG = "optolink";
|
||||
|
||||
void Optolink::comm_() {
|
||||
ESP_LOGD("Optolink", "enter _comm");
|
||||
ESP_LOGD(TAG, "enter _comm");
|
||||
VitoWiFi.readAll();
|
||||
ESP_LOGD("Optolink", "exit _comm");
|
||||
ESP_LOGD(TAG, "exit _comm");
|
||||
}
|
||||
|
||||
void Optolink::setup() {
|
||||
|
@ -52,7 +54,7 @@ void Optolink::set_error(const char *format, ...) {
|
|||
|
||||
void Optolink::read_value(IDatapoint *datapoint) {
|
||||
if (datapoint != nullptr) {
|
||||
ESP_LOGI("Optolink", " read value of datapoint %s", datapoint->getName());
|
||||
ESP_LOGI("Optolink", "requesting value of datapoint %s", datapoint->getName());
|
||||
VitoWiFi.readDatapoint(*datapoint);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +63,7 @@ void Optolink::write_value(IDatapoint *datapoint, DPValue dp_value) {
|
|||
if (datapoint != nullptr) {
|
||||
char buffer[64];
|
||||
dp_value.getString(buffer, sizeof(buffer));
|
||||
ESP_LOGI("Optolink", " write value %s of datapoint %s", buffer, datapoint->getName());
|
||||
ESP_LOGI("Optolink", "sending value %s to datapoint %s", buffer, datapoint->getName());
|
||||
VitoWiFi.writeDatapoint(*datapoint, dp_value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,148 +6,197 @@
|
|||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
void OptolinkSensorBase::update_datapoint_(float value) {
|
||||
if (!writeable_) {
|
||||
optolink_->set_error("try to control not writable number %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "try to control not writable number %s", get_sensor_name().c_str());
|
||||
} else if (datapoint_ != nullptr) {
|
||||
switch (bytes_) {
|
||||
case 1:
|
||||
switch (div_ratio_) {
|
||||
case 1:
|
||||
optolink_->write_value(datapoint_, DPValue((uint8_t) value));
|
||||
break;
|
||||
case 10:
|
||||
optolink_->write_value(datapoint_, DPValue((float) value));
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s",
|
||||
get_sensor_name().c_str());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (div_ratio_) {
|
||||
case 1:
|
||||
optolink_->write_value(datapoint_, DPValue((uint16_t) value));
|
||||
break;
|
||||
case 10:
|
||||
case 100:
|
||||
optolink_->write_value(datapoint_, DPValue((float) value));
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s",
|
||||
get_sensor_name().c_str());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (div_ratio_) {
|
||||
case 1:
|
||||
optolink_->write_value(datapoint_, DPValue((uint32_t) value));
|
||||
break;
|
||||
case 3600:
|
||||
optolink_->write_value(datapoint_, DPValue((float) value));
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s",
|
||||
get_sensor_name().c_str());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte value for number %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte value for number %s", get_sensor_name().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static const char *const TAG = "optolink.sensor_base";
|
||||
|
||||
void OptolinkSensorBase::setup_datapoint_() {
|
||||
switch (bytes_) {
|
||||
void OptolinkSensorBase::setup_datapoint() {
|
||||
switch (div_ratio_) {
|
||||
case 0:
|
||||
datapoint_ = new Datapoint<convRaw>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setLength(bytes_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
uint8_t buffer[bytes_];
|
||||
dp_value.getRaw(buffer);
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO
|
||||
char print_buffer[bytes_ * 2 + 1];
|
||||
dp_value.getString(print_buffer, sizeof(print_buffer));
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %s", dp.getName(), print_buffer);
|
||||
#endif
|
||||
value_changed((uint8_t *) buffer, bytes_);
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
switch (div_ratio_) {
|
||||
switch (bytes_) {
|
||||
case 1:
|
||||
datapoint_ = new Datapoint<conv1_1_US>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_ = new Datapoint<conv1_1_US>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU8());
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU8());
|
||||
value_changed(dp_value.getU8());
|
||||
});
|
||||
break;
|
||||
case 10:
|
||||
datapoint_ = new Datapoint<conv1_10_F>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
case 2:
|
||||
datapoint_ = new Datapoint<conv2_1_US>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (div_ratio_) {
|
||||
case 1:
|
||||
datapoint_ = new Datapoint<conv2_1_US>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU16());
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU16());
|
||||
value_changed(dp_value.getU16());
|
||||
});
|
||||
break;
|
||||
case 10:
|
||||
datapoint_ = new Datapoint<conv2_10_F>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
case 4:
|
||||
datapoint_ = new Datapoint<conv4_1_UL>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
case 100:
|
||||
datapoint_ = new Datapoint<conv2_100_F>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU32());
|
||||
value_changed((uint32_t) dp_value.getU32());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
break;
|
||||
unfitting_value_type();
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (div_ratio_) {
|
||||
case 10:
|
||||
switch (bytes_) {
|
||||
case 1:
|
||||
datapoint_ = new Datapoint<conv4_1_UL>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_ = new Datapoint<conv1_10_F>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU32());
|
||||
value_changed(dp_value.getU32());
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
case 3600:
|
||||
datapoint_ = new Datapoint<conv4_3600_F>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
case 2:
|
||||
datapoint_ = new Datapoint<conv2_10_F>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat());
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str());
|
||||
break;
|
||||
unfitting_value_type();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
optolink_->set_error("Unknown byte value for sensor %s", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSensorBase", "Unknown byte value for sensor %s", get_sensor_name().c_str());
|
||||
case 100:
|
||||
switch (bytes_) {
|
||||
case 2:
|
||||
datapoint_ = new Datapoint<conv2_100_F>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
unfitting_value_type();
|
||||
}
|
||||
break;
|
||||
case 3600:
|
||||
switch (bytes_) {
|
||||
case 4:
|
||||
datapoint_ = new Datapoint<conv4_3600_F>(get_component_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat());
|
||||
value_changed(dp_value.getFloat());
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(float value) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(uint8_t value) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(uint16_t value) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(uint32_t value) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(std::string value) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::value_changed(uint8_t *value, size_t length) {
|
||||
ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(DPValue dp_value) {
|
||||
if (!writeable_) {
|
||||
optolink_->set_error("trying to control not writable datapoint %s", get_component_name().c_str());
|
||||
ESP_LOGE(TAG, "trying to control not writable datapoint %s", get_component_name().c_str());
|
||||
} else if (datapoint_ != nullptr) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO
|
||||
char buffer[100];
|
||||
dp_value.getString(buffer, sizeof(buffer));
|
||||
ESP_LOGI(TAG, "updating datapoint %s value: %s", datapoint_->getName(), buffer);
|
||||
#endif
|
||||
optolink_->write_value(datapoint_, dp_value);
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(float value) {
|
||||
if (div_ratio_ > 1) {
|
||||
update_datapoint(DPValue(value));
|
||||
} else if (div_ratio_ == 1) {
|
||||
switch (bytes_) {
|
||||
case 1:
|
||||
update_datapoint(DPValue((uint8_t) value));
|
||||
break;
|
||||
case 2:
|
||||
update_datapoint(DPValue((uint16_t) value));
|
||||
break;
|
||||
case 4:
|
||||
update_datapoint(DPValue((uint32_t) value));
|
||||
break;
|
||||
default:
|
||||
unfitting_value_type();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(uint8_t value) {
|
||||
if (bytes_ == 1 && div_ratio_ == 1) {
|
||||
update_datapoint(DPValue(value));
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(uint16_t value) {
|
||||
if (bytes_ == 2 && div_ratio_ == 1) {
|
||||
update_datapoint(DPValue(value));
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(uint32_t value) {
|
||||
if (bytes_ == 4 && div_ratio_ == 1) {
|
||||
update_datapoint(DPValue(value));
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::update_datapoint(uint8_t *value, size_t length) {
|
||||
if (bytes_ == length && div_ratio_ == 0) {
|
||||
update_datapoint(DPValue(value, length));
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void OptolinkSensorBase::unfitting_value_type() {
|
||||
optolink_->set_error("Unfitting byte/div_ratio combination for sensor/component %s", get_component_name().c_str());
|
||||
ESP_LOGE(TAG, "Unfitting byte/div_ratio combination for sensor/component %s", get_component_name().c_str());
|
||||
}
|
||||
|
||||
void conv2_100_F::encode(uint8_t *out, DPValue in) {
|
||||
int16_t tmp = floor((in.getFloat() * 100) + 0.5);
|
||||
out[1] = tmp >> 8;
|
||||
|
|
|
@ -12,17 +12,6 @@ namespace optolink {
|
|||
class Optolink;
|
||||
|
||||
class OptolinkSensorBase {
|
||||
protected:
|
||||
Optolink *optolink_;
|
||||
bool writeable_;
|
||||
IDatapoint *datapoint_ = nullptr;
|
||||
uint32_t address_;
|
||||
int bytes_;
|
||||
int div_ratio_ = 1;
|
||||
|
||||
void setup_datapoint_();
|
||||
void update_datapoint_(float value);
|
||||
|
||||
public:
|
||||
OptolinkSensorBase(Optolink *optolink, bool writeable = false) {
|
||||
optolink_ = optolink;
|
||||
|
@ -34,8 +23,31 @@ class OptolinkSensorBase {
|
|||
void set_div_ratio(int div_ratio) { div_ratio_ = div_ratio; }
|
||||
|
||||
protected:
|
||||
virtual const StringRef &get_sensor_name() = 0;
|
||||
virtual void value_changed(float state) = 0;
|
||||
Optolink *optolink_;
|
||||
bool writeable_;
|
||||
IDatapoint *datapoint_ = nullptr;
|
||||
uint32_t address_;
|
||||
size_t bytes_;
|
||||
size_t div_ratio_ = 0;
|
||||
|
||||
virtual const StringRef &get_component_name() = 0;
|
||||
void setup_datapoint();
|
||||
virtual void value_changed(float value);
|
||||
virtual void value_changed(uint8_t value);
|
||||
virtual void value_changed(uint16_t value);
|
||||
virtual void value_changed(uint32_t value);
|
||||
virtual void value_changed(std::string value);
|
||||
virtual void value_changed(uint8_t *value, size_t length);
|
||||
void update_datapoint(float value);
|
||||
void update_datapoint(uint8_t value);
|
||||
void update_datapoint(uint16_t value);
|
||||
void update_datapoint(uint32_t value);
|
||||
void update_datapoint(uint8_t *value, size_t length);
|
||||
|
||||
void unfitting_value_type();
|
||||
|
||||
private:
|
||||
void update_datapoint(DPValue dp_value);
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
|
|
|
@ -10,34 +10,47 @@ namespace optolink {
|
|||
void OptolinkSelect::control(const std::string &value) {
|
||||
for (auto it = mapping_->begin(); it != mapping_->end(); ++it) {
|
||||
if (it->second == value) {
|
||||
ESP_LOGI("OptolinkSelect", "control of select %s to value %s", get_sensor_name().c_str(), it->first.c_str());
|
||||
update_datapoint_(std::stof(it->first));
|
||||
ESP_LOGI("OptolinkSelect", "control of select %s to value %s", get_component_name().c_str(), it->first.c_str());
|
||||
update_datapoint(std::stof(it->first));
|
||||
publish_state(it->second);
|
||||
break;
|
||||
}
|
||||
if (it == mapping_->end()) {
|
||||
optolink_->set_error("unknown value %s of select %s", value.c_str(), get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSelect", "unknown value %s of select %s", value.c_str(), get_sensor_name().c_str());
|
||||
optolink_->set_error("unknown value %s of select %s", value.c_str(), get_component_name().c_str());
|
||||
ESP_LOGE("OptolinkSelect", "unknown value %s of select %s", value.c_str(), get_component_name().c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void OptolinkSelect::value_changed(float state) {
|
||||
std::string key;
|
||||
if (div_ratio_ == 1) {
|
||||
key = std::to_string((int) state);
|
||||
} else {
|
||||
key = std::to_string(state);
|
||||
}
|
||||
void OptolinkSelect::value_changed(std::string key) {
|
||||
auto pos = mapping_->find(key);
|
||||
if (pos == mapping_->end()) {
|
||||
optolink_->set_error("value %s not found in select %s", key.c_str(), get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSelect", "value %s not found in select %s", key.c_str(), get_sensor_name().c_str());
|
||||
optolink_->set_error("value %s not found in select %s", key.c_str(), get_component_name().c_str());
|
||||
ESP_LOGE("OptolinkSelect", "value %s not found in select %s", key.c_str(), get_component_name().c_str());
|
||||
} else {
|
||||
publish_state(pos->second);
|
||||
}
|
||||
//-----------------------------------------------publish_state(state);
|
||||
};
|
||||
}
|
||||
|
||||
void OptolinkSelect::value_changed(uint8_t state) {
|
||||
std::string key = std::to_string(state);
|
||||
value_changed(key);
|
||||
}
|
||||
|
||||
void OptolinkSelect::value_changed(uint16_t state) {
|
||||
std::string key = std::to_string(state);
|
||||
value_changed(key);
|
||||
}
|
||||
|
||||
void OptolinkSelect::value_changed(uint32_t state) {
|
||||
std::string key = std::to_string(state);
|
||||
value_changed(key);
|
||||
}
|
||||
|
||||
void OptolinkSelect::value_changed(float state) {
|
||||
std::string key = std::to_string(state);
|
||||
value_changed(key);
|
||||
}
|
||||
|
||||
} // namespace optolink
|
||||
} // namespace esphome
|
||||
|
|
|
@ -25,10 +25,14 @@ class OptolinkSelect : public OptolinkSensorBase, public esphome::select::Select
|
|||
};
|
||||
|
||||
protected:
|
||||
void setup() override { setup_datapoint_(); }
|
||||
void setup() override { setup_datapoint(); }
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(std::string state) override;
|
||||
void value_changed(uint8_t state) override;
|
||||
void value_changed(uint16_t state) override;
|
||||
void value_changed(uint32_t state) override;
|
||||
void value_changed(float state) override;
|
||||
|
||||
void control(const std::string &value) override;
|
||||
|
|
|
@ -17,11 +17,14 @@ class OptolinkSensor : public OptolinkSensorBase, public esphome::sensor::Sensor
|
|||
}
|
||||
|
||||
protected:
|
||||
void setup() { setup_datapoint_(); }
|
||||
void setup() { setup_datapoint(); }
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(state); };
|
||||
void value_changed(uint8_t state) override { publish_state(state); };
|
||||
void value_changed(uint16_t state) override { publish_state(state); };
|
||||
void value_changed(uint32_t state) override { publish_state(state); };
|
||||
};
|
||||
} // namespace optolink
|
||||
} // namespace esphome
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace optolink {
|
|||
|
||||
void OptolinkSwitch::write_state(bool value) {
|
||||
if (value != 0 && value != 1) {
|
||||
optolink_->set_error("datapoint value of switch %s not 0 or 1", get_sensor_name().c_str());
|
||||
ESP_LOGE("OptolinkSwitch", "datapoint value of switch %s not 0 or 1", get_sensor_name().c_str());
|
||||
optolink_->set_error("datapoint value of switch %s not 0 or 1", get_component_name().c_str());
|
||||
ESP_LOGE("OptolinkSwitch", "datapoint value of switch %s not 0 or 1", get_component_name().c_str());
|
||||
} else {
|
||||
ESP_LOGI("OptolinkSwitch", "control of switch %s to value %d", get_sensor_name().c_str(), value);
|
||||
update_datapoint_(value);
|
||||
ESP_LOGI("OptolinkSwitch", "control of switch %s to value %d", get_component_name().c_str(), value);
|
||||
update_datapoint((uint8_t) value);
|
||||
publish_state(value);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,11 +18,11 @@ class OptolinkSwitch : public OptolinkSensorBase, public esphome::switch_::Switc
|
|||
}
|
||||
|
||||
protected:
|
||||
void setup() override { setup_datapoint_(); }
|
||||
void setup() override { setup_datapoint(); }
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(state); };
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(uint8_t state) override { publish_state(state); };
|
||||
|
||||
void write_state(bool value) override;
|
||||
};
|
||||
|
|
|
@ -5,22 +5,21 @@ from esphome.const import (
|
|||
CONF_ADDRESS,
|
||||
CONF_BYTES,
|
||||
CONF_DIV_RATIO,
|
||||
CONF_ENTITY_ID,
|
||||
CONF_ID,
|
||||
CONF_MODE,
|
||||
)
|
||||
from .. import optolink_ns, CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA
|
||||
|
||||
OptolinkTextSensor = optolink_ns.class_(
|
||||
"OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent
|
||||
)
|
||||
DEPENDENCIES = ["api"]
|
||||
|
||||
TextSensorMode = optolink_ns.enum("TextSensorMode")
|
||||
MODE = {
|
||||
"MAP": TextSensorMode.MAP,
|
||||
"RAW": TextSensorMode.RAW,
|
||||
"DAY_SCHEDULE": TextSensorMode.DAY_SCHEDULE,
|
||||
"DAY_SCHEDULE_SYNCHRONIZED": TextSensorMode.DAY_SCHEDULE_SYNCHRONIZED,
|
||||
}
|
||||
|
||||
DAY_OF_WEEK = {
|
||||
"MONDAY": 0,
|
||||
"TUESDAY": 1,
|
||||
|
@ -30,9 +29,12 @@ DAY_OF_WEEK = {
|
|||
"SATURDAY": 5,
|
||||
"SUNDAY": 6,
|
||||
}
|
||||
|
||||
CONF_DOW = "day_of_week"
|
||||
|
||||
OptolinkTextSensor = optolink_ns.class_(
|
||||
"OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent
|
||||
)
|
||||
|
||||
|
||||
def check_bytes():
|
||||
def validator_(config):
|
||||
|
@ -41,7 +43,9 @@ def check_bytes():
|
|||
if bytes_needed and not bytes_defined:
|
||||
raise cv.Invalid(f"{CONF_BYTES} is required in mode MAP or RAW")
|
||||
if not bytes_needed and bytes_defined:
|
||||
raise cv.Invalid(f"{CONF_BYTES} is not allowed in mode DAY_SCHEDULE")
|
||||
raise cv.Invalid(
|
||||
f"{CONF_BYTES} is not allowed in mode DAY_SCHEDULE and DAY_SCHEDULE_SYNCHRONIZED"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
@ -49,10 +53,39 @@ def check_bytes():
|
|||
|
||||
def check_dow():
|
||||
def validator_(config):
|
||||
if config[CONF_MODE] == "DAY_SCHEDULE" and CONF_DOW not in config:
|
||||
if (
|
||||
config[CONF_MODE] in ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
and CONF_DOW not in config
|
||||
):
|
||||
raise cv.Invalid(f"{CONF_DOW} is required in mode DAY_SCHEDULE")
|
||||
if config[CONF_MODE] != "DAY_SCHEDULE" and CONF_DOW in config:
|
||||
raise cv.Invalid(f"{CONF_DOW} is only allowed in mode DAY_SCHEDULE")
|
||||
if (
|
||||
config[CONF_MODE] not in ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
and CONF_DOW in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_DOW} is only allowed in mode DAY_SCHEDULE or DAY_SCHEDULE_SYNCHRONIZED"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
||||
|
||||
def check_entity_id():
|
||||
def validator_(config):
|
||||
if (
|
||||
config[CONF_MODE] in ["DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
and CONF_ENTITY_ID not in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ENTITY_ID} is required in mode DAY_SCHEDULE_SYNCHRONIZED"
|
||||
)
|
||||
if (
|
||||
config[CONF_MODE] not in ["DAY_SCHEDULE_SYNCHRONIZED"]
|
||||
and CONF_ENTITY_ID in config
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_ENTITY_ID} is only allowed in mode DAY_SCHEDULE_SYNCHRONIZED"
|
||||
)
|
||||
return config
|
||||
|
||||
return validator_
|
||||
|
@ -65,11 +98,13 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.Optional(CONF_MODE, default="MAP"): cv.enum(MODE, upper=True),
|
||||
cv.Optional(CONF_BYTES): cv.int_range(min=1, max=9),
|
||||
cv.Optional(CONF_DOW): cv.enum(DAY_OF_WEEK, upper=True),
|
||||
cv.Optional(CONF_ENTITY_ID): cv.entity_id,
|
||||
}
|
||||
)
|
||||
.extend(SENSOR_BASE_SCHEMA),
|
||||
check_bytes(),
|
||||
check_dow(),
|
||||
check_entity_id(),
|
||||
)
|
||||
|
||||
|
||||
|
@ -87,3 +122,5 @@ async def to_code(config):
|
|||
cg.add(var.set_bytes(config[CONF_BYTES]))
|
||||
if CONF_DOW in config:
|
||||
cg.add(var.set_day_of_week(config[CONF_DOW]))
|
||||
if CONF_ENTITY_ID in config:
|
||||
cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
static const char *const TAG = "optolink.text_sensor";
|
||||
|
||||
void OptolinkDeviceInfoSensor::setup() {
|
||||
datapoint_ = new Datapoint<conv4_1_UL>(get_name().c_str(), "optolink", 0x00f8, false);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
uint32_t value = dp_value.getU32();
|
||||
ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), value);
|
||||
ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), value);
|
||||
uint8_t *bytes = (uint8_t *) &value;
|
||||
uint16_t tmp = esphome::byteswap(*((uint16_t *) bytes));
|
||||
std::string geraetekennung = esphome::format_hex_pretty(&tmp, 1);
|
||||
|
|
|
@ -2,43 +2,139 @@
|
|||
|
||||
#include "optolink_text_sensor.h"
|
||||
#include "../optolink.h"
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#include "VitoWiFi.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
static const char *const TAG = "optolink.text_sensor";
|
||||
|
||||
struct Time {
|
||||
int hours;
|
||||
int minutes;
|
||||
};
|
||||
|
||||
bool check_time_sequence(const Time &t1, const Time &t2) {
|
||||
if (t2.hours > t1.hours || (t2.hours == t1.hours && t2.minutes >= t1.minutes)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_time_values(const Time &time) {
|
||||
return (time.hours >= 0 && time.hours <= 23) && (time.minutes >= 0 && time.minutes <= 59);
|
||||
}
|
||||
|
||||
uint8_t *encode_time_string(std::string input) {
|
||||
std::istringstream iss(input);
|
||||
std::vector<Time> time_values;
|
||||
|
||||
Time prev_time = {0, 0};
|
||||
|
||||
while (iss) {
|
||||
std::string time_string;
|
||||
iss >> time_string;
|
||||
|
||||
if (time_string.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Time current_time;
|
||||
if (sscanf(time_string.c_str(), "%d:%d", ¤t_time.hours, ¤t_time.minutes) == 2) {
|
||||
if (check_time_values(current_time) && check_time_sequence(prev_time, current_time)) {
|
||||
time_values.push_back(current_time);
|
||||
prev_time = current_time;
|
||||
} else {
|
||||
ESP_LOGE(
|
||||
TAG,
|
||||
"Time values should be in the format hh:mm and in increasing order within the range of 00:00 to 23:59");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid time format");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (time_values.size() > 8) {
|
||||
ESP_LOGE(TAG, "Maximum 8 time values allowed");
|
||||
return 0;
|
||||
}
|
||||
if (time_values.size() % 2) {
|
||||
ESP_LOGE(TAG, "Number of time values must be even");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (time_values.size() < 8) {
|
||||
time_values.push_back({31, 70});
|
||||
}
|
||||
|
||||
static uint8_t data[8];
|
||||
// ESP_LOGD(TAG, "Parsed time values:");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
Time time = time_values[i];
|
||||
data[i] = (time.hours << 3) + (time.minutes / 10);
|
||||
// ESP_LOGD(TAG, " %02d:%02d => %d", time.hours, time.minutes, data[i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void OptolinkTextSensor::setup() {
|
||||
if (mode_ == RAW) {
|
||||
datapoint_ = new Datapoint<convRaw>(get_sensor_name().c_str(), "optolink", address_, writeable_);
|
||||
datapoint_->setLength(bytes_);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
uint8_t buffer[bytes_ + 1];
|
||||
dp_value.getRaw(buffer);
|
||||
buffer[bytes_] = 0x0;
|
||||
ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s: %s", dp.getGroup(), dp.getName(), buffer);
|
||||
publish_state((char *) buffer);
|
||||
});
|
||||
div_ratio_ = 0;
|
||||
} else if (mode_ == DAY_SCHEDULE) {
|
||||
datapoint_ = new Datapoint<convRaw>(get_sensor_name().c_str(), "optolink", address_ + 8 * dow_, writeable_);
|
||||
datapoint_->setLength(8);
|
||||
datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) {
|
||||
uint8_t data[8];
|
||||
dp_value.getRaw(data);
|
||||
ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s", dp.getGroup(), dp.getName());
|
||||
char buffer[100];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (data[i] != 0xFF) {
|
||||
int hour = data[i] >> 3;
|
||||
int minute = (data[i] & 0b111) * 10;
|
||||
sprintf(buffer + i * 6, "%02d:%02d ", hour, minute);
|
||||
} else {
|
||||
sprintf(buffer + i * 6, " ");
|
||||
div_ratio_ = 0;
|
||||
bytes_ = 8;
|
||||
address_ += (8 * dow_);
|
||||
} else if (mode_ == DAY_SCHEDULE_SYNCHRONIZED) {
|
||||
writeable_ = true;
|
||||
div_ratio_ = 0;
|
||||
bytes_ = 8;
|
||||
address_ += (8 * dow_);
|
||||
api::global_api_server->subscribe_home_assistant_state(
|
||||
this->entity_id_, optional<std::string>(), [this](const std::string &state) {
|
||||
ESP_LOGD(TAG, "got time values from entity '%s': %s", this->entity_id_.c_str(), state.c_str());
|
||||
uint8_t *data = encode_time_string(state);
|
||||
if (data) {
|
||||
update_datapoint(data, 8);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "not changing any value of datapoint %s", datapoint_->getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
setup_datapoint();
|
||||
};
|
||||
|
||||
void OptolinkTextSensor::value_changed(uint8_t *state, size_t length) {
|
||||
switch (mode_) {
|
||||
case RAW:
|
||||
publish_state(std::string((const char *) state));
|
||||
break;
|
||||
case DAY_SCHEDULE:
|
||||
case DAY_SCHEDULE_SYNCHRONIZED:
|
||||
if (length == 8) {
|
||||
char buffer[6 * length + 1];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int hour = state[i] >> 3;
|
||||
int minute = (state[i] & 0b111) * 10;
|
||||
if (state[i] != 0xFF) {
|
||||
sprintf(buffer + i * 6, "%02d:%02d ", hour, minute);
|
||||
} else {
|
||||
sprintf(buffer + i * 6, " ");
|
||||
}
|
||||
}
|
||||
publish_state(buffer);
|
||||
} else {
|
||||
unfitting_value_type();
|
||||
}
|
||||
publish_state(buffer);
|
||||
});
|
||||
} else {
|
||||
setup_datapoint_();
|
||||
break;
|
||||
case MAP:
|
||||
unfitting_value_type();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
namespace esphome {
|
||||
namespace optolink {
|
||||
|
||||
enum TextSensorMode { MAP, RAW, DAY_SCHEDULE };
|
||||
enum TextSensorMode { MAP, RAW, DAY_SCHEDULE, DAY_SCHEDULE_SYNCHRONIZED };
|
||||
|
||||
class OptolinkTextSensor : public OptolinkSensorBase,
|
||||
public esphome::text_sensor::TextSensor,
|
||||
|
@ -20,17 +20,23 @@ class OptolinkTextSensor : public OptolinkSensorBase,
|
|||
|
||||
void set_mode(TextSensorMode mode) { mode_ = mode; }
|
||||
void set_day_of_week(int dow) { dow_ = dow; }
|
||||
void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; }
|
||||
|
||||
protected:
|
||||
void setup() override;
|
||||
void update() override { optolink_->read_value(datapoint_); }
|
||||
|
||||
const StringRef &get_sensor_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(std::to_string((uint32_t) state)); };
|
||||
const StringRef &get_component_name() override { return get_name(); }
|
||||
void value_changed(float state) override { publish_state(std::to_string(state)); };
|
||||
void value_changed(uint8_t state) override { publish_state(std::to_string(state)); };
|
||||
void value_changed(uint16_t state) override { publish_state(std::to_string(state)); };
|
||||
void value_changed(uint32_t state) override { publish_state(std::to_string(state)); };
|
||||
void value_changed(uint8_t *state, size_t length) override;
|
||||
|
||||
private:
|
||||
TextSensorMode mode_ = MAP;
|
||||
int dow_ = 0;
|
||||
std::string entity_id_;
|
||||
};
|
||||
|
||||
} // namespace optolink
|
||||
|
|
Loading…
Add table
Reference in a new issue