ESPHome 2026.5.1
Loading...
Searching...
No Matches
alpha3.cpp
Go to the documentation of this file.
1#include "alpha3.h"
2#include "esphome/core/log.h"
4#include <lwip/sockets.h> //gives ntohl
5
6#ifdef USE_ESP32
7
8namespace esphome::alpha3 {
9
10static const char *const TAG = "alpha3";
11
13 ESP_LOGCONFIG(TAG, "ALPHA3");
14 LOG_SENSOR(" ", "Flow", this->flow_sensor_);
15 LOG_SENSOR(" ", "Head", this->head_sensor_);
16 LOG_SENSOR(" ", "Power", this->power_sensor_);
17 LOG_SENSOR(" ", "Current", this->current_sensor_);
18 LOG_SENSOR(" ", "Speed", this->speed_sensor_);
19 LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
20}
21
23
24void Alpha3::extract_publish_sensor_value_(const uint8_t *response, int16_t length, int16_t response_offset,
25 int16_t value_offset, sensor::Sensor *sensor, float factor) {
26 if (sensor == nullptr)
27 return;
28 // we need to handle cases where a value is split over two packets
29 const int16_t value_length = 4; // 32bit float
30 // offset inside current response packet
31 auto rel_offset = value_offset - response_offset;
32 if (rel_offset <= -value_length)
33 return; // aready passed the value completly
34 if (rel_offset >= length)
35 return; // value not in this packet
36
37 auto start_offset = std::max(0, rel_offset);
38 auto end_offset = std::min((int16_t) (rel_offset + value_length), length);
39 auto copy_length = end_offset - start_offset;
40 auto buffer_offset = std::max(-rel_offset, 0);
41 std::memcpy(this->buffer_ + buffer_offset, response + start_offset, copy_length);
42
43 if (rel_offset + value_length <= length) {
44 // we have the whole value
45 void *buffer = this->buffer_; // to prevent warnings when casting the pointer
46 *((int32_t *) buffer) = ntohl(*((int32_t *) buffer)); // values are big endian
47 float fvalue = *((float *) buffer);
48 sensor->publish_state(fvalue * factor);
49 }
50}
51
52bool Alpha3::is_current_response_type_(const uint8_t *response_type) {
53 return !std::memcmp(this->response_type_, response_type, GENI_RESPONSE_TYPE_LENGTH);
54}
55
56void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) {
57 if (this->response_offset_ >= this->response_length_) {
58 ESP_LOGD(TAG, "[%s] GENI response begin", this->parent_->address_str());
59 if (length < GENI_RESPONSE_HEADER_LENGTH) {
60 ESP_LOGW(TAG, "[%s] response too short", this->parent_->address_str());
61 return;
62 }
63 if (response[0] != 36 || response[2] != 248 || response[3] != 231 || response[4] != 10) {
64 ESP_LOGW(TAG, "[%s] response bytes %d %d %d %d %d don't match GENI HEADER", this->parent_->address_str(),
65 response[0], response[1], response[2], response[3], response[4]);
66 return;
67 }
68 this->response_length_ = response[1] - GENI_RESPONSE_HEADER_LENGTH + 2; // maybe 2 byte checksum
69 this->response_offset_ = -GENI_RESPONSE_HEADER_LENGTH;
70 std::memcpy(this->response_type_, response + 5, GENI_RESPONSE_TYPE_LENGTH);
71 }
72
73 auto extract_publish_sensor_value = [response, length, this](int16_t value_offset, sensor::Sensor *sensor,
74 float factor) {
75 this->extract_publish_sensor_value_(response, length, this->response_offset_, value_offset, sensor, factor);
76 };
77
78 if (this->is_current_response_type_(GENI_RESPONSE_TYPE_FLOW_HEAD)) {
79 ESP_LOGD(TAG, "[%s] FLOW HEAD Response", this->parent_->address_str());
80 extract_publish_sensor_value(GENI_RESPONSE_FLOW_OFFSET, this->flow_sensor_, 3600.0F);
81 extract_publish_sensor_value(GENI_RESPONSE_HEAD_OFFSET, this->head_sensor_, .0001F);
82 } else if (this->is_current_response_type_(GENI_RESPONSE_TYPE_POWER)) {
83 ESP_LOGD(TAG, "[%s] POWER Response", this->parent_->address_str());
84 extract_publish_sensor_value(GENI_RESPONSE_POWER_OFFSET, this->power_sensor_, 1.0F);
85 extract_publish_sensor_value(GENI_RESPONSE_CURRENT_OFFSET, this->current_sensor_, 1.0F);
86 extract_publish_sensor_value(GENI_RESPONSE_MOTOR_SPEED_OFFSET, this->speed_sensor_, 1.0F);
87 extract_publish_sensor_value(GENI_RESPONSE_VOLTAGE_AC_OFFSET, this->voltage_sensor_, 1.0F);
88 } else {
89 ESP_LOGW(TAG, "unkown GENI response Type %d %d %d %d %d %d %d %d", this->response_type_[0], this->response_type_[1],
90 this->response_type_[2], this->response_type_[3], this->response_type_[4], this->response_type_[5],
91 this->response_type_[6], this->response_type_[7]);
92 }
93 this->response_offset_ += length;
94}
95
96void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
97 switch (event) {
98 case ESP_GATTC_OPEN_EVT: {
99 if (param->open.status == ESP_GATT_OK) {
100 this->response_offset_ = 0;
101 this->response_length_ = 0;
102 ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str());
103 }
104 break;
105 }
106 case ESP_GATTC_CONNECT_EVT: {
107 if (std::memcmp(param->connect.remote_bda, this->parent_->get_remote_bda(), 6) != 0)
108 return;
109 auto ret = esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT);
110 if (ret) {
111 ESP_LOGW(TAG, "esp_ble_set_encryption failed, status=%x", ret);
112 }
113 break;
114 }
115 case ESP_GATTC_DISCONNECT_EVT: {
116 this->node_state = espbt::ClientState::IDLE;
117 if (this->flow_sensor_ != nullptr)
118 this->flow_sensor_->publish_state(NAN);
119 if (this->head_sensor_ != nullptr)
120 this->head_sensor_->publish_state(NAN);
121 if (this->power_sensor_ != nullptr)
122 this->power_sensor_->publish_state(NAN);
123 if (this->current_sensor_ != nullptr)
124 this->current_sensor_->publish_state(NAN);
125 if (this->speed_sensor_ != nullptr)
126 this->speed_sensor_->publish_state(NAN);
127 if (this->voltage_sensor_ != nullptr)
128 this->voltage_sensor_->publish_state(NAN);
129 break;
130 }
131 case ESP_GATTC_SEARCH_CMPL_EVT: {
132 auto *chr = this->parent_->get_characteristic(ALPHA3_GENI_SERVICE_UUID, ALPHA3_GENI_CHARACTERISTIC_UUID);
133 if (chr == nullptr) {
134 ESP_LOGE(TAG, "[%s] No GENI service found at device, not an Alpha3..?", this->parent_->address_str());
135 break;
136 }
137 auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
138 chr->handle);
139 if (status) {
140 ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
141 }
142 this->geni_handle_ = chr->handle;
143 break;
144 }
145 case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
146 this->node_state = espbt::ClientState::ESTABLISHED;
147 this->update();
148 break;
149 }
150 case ESP_GATTC_NOTIFY_EVT: {
151 if (param->notify.handle == this->geni_handle_) {
152 this->handle_geni_response_(param->notify.value, param->notify.value_len);
153 }
154 break;
155 }
156 default:
157 break;
158 }
159}
160
161void Alpha3::send_request_(uint8_t *request, size_t len) {
162 auto status =
163 esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->geni_handle_, len,
164 request, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
165 if (status)
166 ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
167}
168
170 if (this->node_state != espbt::ClientState::ESTABLISHED) {
171 ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str());
172 return;
173 }
174
175 if (this->flow_sensor_ != nullptr || this->head_sensor_ != nullptr) {
176 uint8_t geni_request_flow_head[] = {39, 7, 231, 248, 10, 3, 93, 1, 33, 82, 31};
177 this->send_request_(geni_request_flow_head, sizeof(geni_request_flow_head));
178 delay(25); // need to wait between requests
179 }
180 if (this->power_sensor_ != nullptr || this->current_sensor_ != nullptr || this->speed_sensor_ != nullptr ||
181 this->voltage_sensor_ != nullptr) {
182 uint8_t geni_request_power[] = {39, 7, 231, 248, 10, 3, 87, 0, 69, 138, 205};
183 this->send_request_(geni_request_power, sizeof(geni_request_power));
184 delay(25); // need to wait between requests
185 }
186}
187} // namespace esphome::alpha3
188
189#endif
uint8_t status
Definition bl0942.h:8
uint8_t buffer_[4]
Definition alpha3.h:59
void handle_geni_response_(const uint8_t *response, uint16_t length)
Definition alpha3.cpp:56
bool is_current_response_type_(const uint8_t *response_type)
Definition alpha3.cpp:52
sensor::Sensor * head_sensor_
Definition alpha3.h:50
sensor::Sensor * flow_sensor_
Definition alpha3.h:49
uint8_t response_type_[GENI_RESPONSE_TYPE_LENGTH]
Definition alpha3.h:58
sensor::Sensor * voltage_sensor_
Definition alpha3.h:54
void setup() override
Definition alpha3.cpp:22
void send_request_(uint8_t *request, size_t len)
Definition alpha3.cpp:161
int16_t response_length_
Definition alpha3.h:56
sensor::Sensor * speed_sensor_
Definition alpha3.h:53
sensor::Sensor * power_sensor_
Definition alpha3.h:51
void update() override
Definition alpha3.cpp:169
int16_t response_offset_
Definition alpha3.h:57
void extract_publish_sensor_value_(const uint8_t *response, int16_t length, int16_t response_offset, int16_t value_offset, sensor::Sensor *sensor, float factor)
Definition alpha3.cpp:24
sensor::Sensor * current_sensor_
Definition alpha3.h:52
void dump_config() override
Definition alpha3.cpp:12
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override
Definition alpha3.cpp:96
uint16_t geni_handle_
Definition alpha3.h:55
BLECharacteristic * get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr)
Base-class for all sensors.
Definition sensor.h:47
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
std::string size_t len
void HOT delay(uint32_t ms)
Definition hal.cpp:85
uint16_t length
Definition tt21100.cpp:0